htmlでキャンバスベースのスクリーンショットを行う小さなデモ
上部に書かれている
以前、みんなのシェアでjsを使ったスクリーンショットソリューションの説明を見た記憶があるのですが、詳細は覚えていませんが、canvasを使っているようで結構面白かった記憶があるので、今回は作者の思いを共有するために自分で書いてみる予定です。これはごく簡単な小さなデモですが、もしバグがあればissueに言及してください。 コードアドレス
レンダリング
全体的な感想
- 開始/終了のショートカットを設定
- 起動後にDOMをcanvasに描画し、元のDOMインターフェースを上書きする
- マウスのスクリーンショット領域をシミュレートするためのキャンバスを追加する
- マウスのスクリーンショット領域に対応するブラウザのインターフェイスを描くためのキャンバスを追加します(最初のキャンバスから取得)。
- インターセプトした画像を保存する
1. 開始/終了ショートカットキーの設定
最初のパラメータは配列として渡されます。これは、ショートカットによって引き起こされる潜在的な競合のために、開始ショートカットの数は無制限であることが望ましいからです。
function screenShot(quickStartKey, EndKey) {
// Compatibility considerations do not use... Extended String
var keyLength = quickStartKey.length
var isKeyTrigger = {}
var cantStartShot = false
...
quickStartKey.forEach(function(item) { // iterate through the array of parameters
isKeyTrigger[item] = false // by default all keys in the array are not triggered
})
$('html').on('keyup', function(e) {
var keyCode = e.which
if(keyCode === EndKey) {
...
} else if(!cantStartShot) {
isKeyTrigger[keyCode] = true
var notTrigger = Object.keys(isKeyTrigger).filter(function(item) {
return isKeyTrigger[item] === false // check if there is a shortcut key that needs to be triggered
})
if(notTrigger.length === 0) { //no shortcut key to be triggered that can start the screenshot
cantStartShot = true
beginShot(cantStartShot)
}
}
})
2. DOMをキャンバスとして描画し、本来のDOMインターフェースをオーバーライドする
ネイティブなアプローチを使う場合は MDN で、Canvas での DOM の描画について紹介しています。厄介なのは、要素 <foreignObject> を含む XML を含む SVG 画像を作成する必要がある点です。現在のブラウザが表示しているDOMをどうやって計算して取り出すかが、実は一番面倒なのです。まあ実際、筆者は手動で実装する名案を持っていないので =. =、これが選ばれました。 html2canvas というライブラリがあります。大まかには以下のように呼ばれます。
function beginShot(cantStartShot) {
if(cantStartShot) {
html2canvas(document.body, {
onrendered: function(canvas) {
// get a canvas image that matches the interface
}
})
}
}
3. マウスのスクリーンショット領域をシミュレートするためのキャンバスを追加する
この領域の実装は、当初ネイティブの canvas API を使用する予定でしたが、マウスを押してドラッグした後にリアルタイムで canvas を描画する必要があるため、PS レイヤーと同様のコンセプトで、マウス移動のたびに現在のスクリーンショット ボックスを描画し、次のマウス移動が発生すると前のスクリーンショット ボックスを削除するという問題が発生しました。これは、リアルタイムの描画処理をシミュレートするためです。作者はcanvasネイティブAPIを使う方法を見つけられませんでしたが、もしそうなら、描画された画像に印をつける方法を教えてください。ここでは、著者はJqのcanvasをベースにしたライブラリである Jcanvas これは、レイヤーの概念、すなわち、1つのレイヤーに1つだけ描画することと、レイヤーに名前を付けてタグ付けする機能を提供します。これは著者のニーズを満たすもので、次のように実装されている。
$('#' + canvasId).mousedown(function(e) {
$("#"+canvasId).removeLayer(layerName) // remove the previous layer
layerName += 1
startX = that._calculateXY(e).x //calculate mouse position
startY = that._calculateXY(e).y
isShot = true
$("#"+canvasId).addLayer({
type: 'rectangle', //rectangle
...
name:layerName, //the name of the layer
x: startX,
y: startY,
width: 1,
height: 1
})
}).mousemove(function(e) {
if(isShot) {
$("#"+canvasId).removeLayer(layerName)
var moveX = that._calculateXY(e).x
var moveY = that._calculateXY(e).y
var width = moveX - startX
var height = moveY - startY
$("#"+canvasId).addLayer({
type: 'rectangle',
...
name:layerName,
fromCenter: false,
x: startX,
y: startY,
width: width,
height: height
})
$("#"+canvasId).drawLayers(); //draw
}
})
4. マウスのスクリーンショット領域に対応するブラウザインターフェースを描画するためのキャンバスを追加する
var canvasResult = document.getElementById('canvasResult')
var ctx = canvasResult.getContext("2d");
ctx.drawImage(copyDomCanvas, moveX - startX > 0 ? startX : moveX, moveY - startY > 0 ? startY : moveY, width, height, 0, 0, width, height )
var dataURL = canvasResult.toDataURL("image/png");
ここで、画像は drawImage によってインターセプトされ、toDataURL メソッドで base64 に変換されます。
5. インターセプトした画像の保存
function downloadFile(el, fileName, href){
el.attr({
'download':fileName,
'href': href
})
}
...
downloadFile($('.ok'), 'screenShot' + Math.random().toString().split('.') [1] || Math.random() + '.png', dataURL)
// Pass in the key object, the image to save the random name, and the base64-encoded image
を使用します。 ダウンロードのaタグ 属性があり、これをクリックすると直接ダウンロードできるようになっています。
デプロイメント
依存関係
<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/jcanvas/16.7.3/jcanvas.min.js"></script>
<script src="https://cdn.bootcss.com/html2canvas/0.5.0-beta4/html2canvas.min.js"></script>
設定用ショートカット
screenShot([16, 65], 27) // start shortcut is set to shift+a; exit key is ESC
最後に
本文中の一番厄介な部分(DOMからcanvasへの書き込み、canvasのレイヤー設定)はそれぞれ2つのライブラリを使って実装されており、筆者はこれらの操作をネイティブAPIを使って実装する方法を中心にフォローしていきますが、個人的には自分で書くのはまだちょっと難しいかな、と思っています。
以上が今回の内容の全てです。勉強になると思いますし、スクリプトハウスをもっと応援して頂ければと思います。
関連
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン