お絵かきできるSNSを作りたい!9


お絵かきできるSNSを作りたい後半戦、下のメニューを作っていきます。

まずはPNGで保存機能。

function saveCanvas(){
    var src1_img = new Image();
    var src2_img = new Image();
    src1_img.src = $("#canvas")[0].toDataURL();
    src1_img.addEventListener('load', function() {
        src2_img.src = $("#canvas2")[0].toDataURL();
        src2_img.addEventListener('load', function() {
            var dst_canvas = document.createElement('canvas');
            dst_canvas.width = 800;
            dst_canvas.height = 600;
            dst_canvas.getContext("2d").drawImage(src1_img, 0, 0, 800, 600);
            dst_canvas.getContext("2d").drawImage(src2_img, 0, 0, 800, 600);

            var imageType = "image/png";
            var fileName = "download.png";
            // base64エンコードされたデータを取得 「data:image/png;base64,iVBORw0k~」
            var base64 = dst_canvas.toDataURL(imageType);
            // base64データをblobに変換
            var blob = Base64toBlob(base64);
            // blobデータをa要素を使ってダウンロード
            saveBlob(blob, fileName);
        }, false);
    }, false);
}

// Base64データをBlobデータに変換
function Base64toBlob(base64){
    // カンマで分割して以下のようにデータを分ける
    // tmp[0] : データ形式(data:image/png;base64)
    // tmp[1] : base64データ(iVBORw0k~)
    var tmp = base64.split(',');
    // base64データの文字列をデコード
    var data = atob(tmp[1]);
    // tmp[0]の文字列(data:image/png;base64)からコンテンツタイプ(image/png)部分を取得
    var mime = tmp[0].split(':')[1].split(';')[0];
    //  1文字ごとにUTF-16コードを表す 0から65535 の整数を取得
    var buf = new Uint8Array(data.length);
    for (var i = 0; i < data.length; i++) {
        buf[i] = data.charCodeAt(i);
    }
    // blobデータを作成
    var blob = new Blob([buf], { type: mime });
    return blob;
}

// 画像のダウンロード
function saveBlob(blob, fileName){
    var url = (window.URL || window.webkitURL);
    // ダウンロード用のURL作成
    var dataUrl = url.createObjectURL(blob);
    // イベント作成
    var event = document.createEvent("MouseEvents");
    event.initMouseEvent("click", true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
    // a要素を作成
    var a = document.createElementNS("http://www.w3.org/1999/xhtml", "a");
    // ダウンロード用のURLセット
    a.href = dataUrl;
    // ファイル名セット
    a.download = fileName;
    // イベントの発火
    a.dispatchEvent(event);
}

無駄に関数が増えました。
レイヤーが2枚あるので1枚にがっちゃんこしてます。
[github]修正内容はこちら

次はフルスクリーンボタンの実装です。

var blFullscreen = true;
function doFullscreen(){
    var elem = document.getElementById("screen");
    if (blFullscreen){
        if (elem.requestFullscreen) {
          elem.requestFullscreen();
        } else if (elem.webkitRequestFullScreen) {
          elem.webkitRequestFullScreen();
        } else if (elem.mozRequestFullScreen) {
          elem.mozRequestFullScreen();
        } else if (elem.msRequestFullscreen) {
          elem.msRequestFullscreen();
        }
        blFullscreen = false;
    } else {
        if (document.webkitCancelFullScreen) {
            document.webkitCancelFullScreen();
        } else if (document.mozCancelFullScreen) {
            document.mozCancelFullScreen();
        } else if (document.msExitFullscreen) {
            document.msExitFullscreen();
        } else if(document.cancelFullScreen) {
            document.cancelFullScreen();
        } else if(document.exitFullscreen) {
            document.exitFullscreen();
        }
        blFullscreen = true;
    }
}

フルスクリーン状態の判定をJSで行おうとするとブラウザによって挙動が怪しくなり悩むくらいならとグローバルおじさんになりました。

あと細かい修正もしたので詳しくは↓こちらを。
[github]修正内容はこちら

そして、左右反転。
これがちょっと手間で、左右反転するとレイヤー1とレイヤー2のX座標も反転させています。
メインの関数は↓こちら。

var blReflect = true;
function doReflect(){
    if (blReflect){
        $("#canvas").css('transform', 'scale(-1, 1)');
        $("#canvas2").css('transform', 'scale(-1, 1)');
        blReflect = false;
    } else {
        $("#canvas").css('transform', 'scale(1, 1)');
        $("#canvas2").css('transform', 'scale(1, 1)');
        blReflect = true;
    }
}

あとは、押したとき、動かしている時、離したときに左右反転状態かを判定してX座標を左右逆になるようにしました。

        if (blReflect) {
            ox=event.clientX-event.target.getBoundingClientRect().left;
        } else {
            ox=$("#canvas").width() + (parseInt($("body").css('padding-left')) * 2) - event.clientX-event.target.getBoundingClientRect().left;
        }

[github]修正内容はこちら

今回最後は最初から書き直すの実装です。
これはページリロードでいいんじゃ・・?とも思いましたが、折角なのでちゃんと実装しました。

function doClear(){
    if(confirm('本当にいいんですね?')){
        ct.clearRect(0, 0, $("#canvas").width(), $("#canvas").height());
        ct2.clearRect(0, 0, $("#canvas2").width(), $("#canvas2").height());
    }
}

ちゃんとアラートで消すことを確認する新設設計。
レイヤー1とレイヤー2をクリアしています。

[github]修正内容はこちら

次回、Ctrl+Zをしたい。お楽しみに。

次:お絵かきできるSNSを作りたい!10
最初:お絵かきできるSNSを作りたい!