スポンサーサイト

2014.01.27 Monday

一定期間更新がないため広告を表示しています

  • -
  • -
  • -

iOS6がリリースされiPhone5が発売されました。

いままでスマホなんてまったく興味がなかったのに。

まったく興味がなかったので4の発売直前に

3GSを買ってからだんだんとiPhoneの魅力に、、、。

それ以来この発表が楽しみになってしまいました。

すごいなapple。

現在JB4Sを使用中ですが5は見送りま〜す。

欲しいですが。

ちなみにちょっと友達の5使わせてもらったんですが、

処理がメッチャ早い!そして軽い!すごい!

iOS6よりinput type="file"が使える!fileReaderも使える!

以下fileReaderに関するメモです。。


iPhoneってinput type="file"が使えなかったんですよね。


これ結構残念な仕様だなぁとずっと思ってました。


それがついに開放!


そしてこのブログでも長いことひっぱてますお絵かきアプリ、


以前作ってみた時、撮った写真にお絵かきできたらいいな、


と思ったのですが、


まぁ、まずファイルにアクセスできないし、ブラウザだけで


完結できないし、とか考えつつあきらめていたのですが、


iOS6にて両方いけるようになったのでとりあえず試してみました。


ちなみに1点残念な事がありまして、どーやらwindows版safariの


提供が終了してしまったようで、win safariはfileReaderが使えないまま


最後を迎えてしまったようです。。。


まずはinput type="file"のデザインをCSSでこっそり隠す

input type="file"ってそーいえばデザインどーする?!


とちょっとググってみたら、透明にして重ねる!みたいな記事が


結構ヒット。やっぱり同じ悩みを持つ方は結構いるんだなと。


html

<ul>
    <li>写真にお絵かき<input type="file" id="fake" /></li>
    <li>・・・・</li>
    <li>・・・・</li>
    <li>・・・・</li>
</ul>

css

li {
	line-height: 75px;
	position: relative;
	margin: 0 auto;
	width: 320px;
}
#fake {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	opacity: 0;
}
一応webkit系であればli全体がクリックできた

のですが他ブラウザは(あまり確認してませんが、、、)デフォルトの

ボタン部分をちゃんとクリックしないと認識できなかった為

かなり危険なデザインです。はい。


ファイルを選択してcanvasへ描き出す


var tar = $("#illustMenu li");
//input type file、fileReader使える??
if(!window.FileReader || $('#fake').get(0).disabled) $(tar[0]).css('display', 'none');
 
$("#illustMenu li").bind("click", function() {
    scrollTo(0, 0);
    var index = $("#illustMenu li").index(this);
    var myImg = new Image();
    if(!index) {
        var $fake = $('#fake').get(0);
        $fake.onchange = function() {
            var file = $fake.files[0];
            if(!file.type.match('image.*')) {
                alert('画像以外は読込めません');
                return;
            };
            var fr = new FileReader();
            fr.onload = function() {
                myImg.src = fr.result;
                callback();
            };
            fr.onerror = function() {
                alert('読込めませんでした');
            };
            fr.readAsDataURL(file);
        };
    } else {
        myImg.src = "img/illust/" + index + ".png";
        callback();
    };
    function callback() {
        myImg.onload = function() {
            var iw = myImg.width;
            var ih = myImg.height;
            if(!index) {
                ・・・・・
                ・・・・・
            };
            if(W > 600 && !retina) {
                ctx.drawImage(myImg, 0, 0, iw, ih);
            } else {
                ctx.drawImage(myImg, 0, 0, iw/2, ih/2);
            };
        };
    };
});
とりあえずfileReaderが使えるか?input type fileが使えるか?

使えれば「写真にお絵かき」メニューを表示する。

onchangeイベントにて以下実行。

fileapiにてファイルにアクセスしてfileReaderで読み込む。

readAsDataURL()メソッドでDataURLスキームに変換して読み込む。

そしてonloadイベントで画像サイズを調整してcanvasに描画。

OK。以外とあっさり。よかった。

PCで確認する分には。



ここからどっぷりはまりました、、、、。

ではiPhoneで確認。


問題なくファイル選択画面登場。


適当な写真を選択。


まったくもってきちんと描画されない、、、、。


縦、横もおかしい。


ググってググってまたググって。


そこでふと思い出したMobileSafariのリソース制限。


これかぁ。


canvasにリサイズして書き出したくても


どーにもきちんと読み込まれない。


これはやっぱりimageオブジェクトで読み込んだ時


おかしくなってるのか??


上限35メガピクセル。


iPhone4sのカメラは800万画素で8メガピクセル。


ただ2メガピクセル以上はうんたらかんたら。


よくわからん。


さらにcanvasの上限は2メガバイト。


よくわからん。


とりあえずの結果

まず4sで撮影したデフォルト画像はcanvasに書き出した際


おかしなことになる。さらに縦・横認識していない。


しかしフォトストリームから読み込むと問題なく書き出され


縦・横も認識される。


iPad2で撮影したデフォルト画像はcanvasに書き出した際


きちんと書き出されるが縦・横が認識されていない?


ただiPad2で4sで撮影したフォトストリームの画像は


問題なく書き出され縦・横も認識された。


3GSではフォトストリームの画像もおかしなことに、、、。


うーんよくわからん。


おそらくそのRAMとリソース制限の関係でしょうか??


もう少しつっこんで

描きだし時にバグるのはしょうがないとして

なぜ縦・横を認識しない?

ググってみると画像にはExifという画像の様々なデータ

が書き込まれたものがあると。なるほど。

そんでそれはバイナリデータで抽出可能。


なんともめんどくさそう。


fileapiに出会った時これは一体何に使うんだ?


と思っていったreadAsArrayBuffer。


バイナリデータを読み込めます。


まさか早速お世話になるとは。


JPEG画像からExif情報を抽出する


未知な世界のバイナリ。


ということでとりあえず上のコードをお借りして


いったんExifデータを確認させていただくと、


しっかりorientation6又は1となってる。


これで分岐すればとりあえず対応はできそう。


そのうちバイナリの勉強でもしよう。


さいごに

まともには使えませんがとりあえず実装してみました。


お絵かきアプリ


それとあまり関係ありませんがgetImageDataで取得した


imageDataオブジェクトをputImageDataで描き出す際


変換マトリックスを適用する方法ご存知の方いませんでしょうか??


回転させたいだけなんですが、、、。ご存知の方コメントいただけたら


うれしいです。


いつもいつも簡単に終わるかなと思って取り掛かるんですが、


予想外の時間がかかってしまいます。


いい加減他の勉強を始めなければ、、、



相変わらず広告が挿入されております。

更新頻度が少なすぎる。。。

とあるサイトをとりあえずスマホに対応させたいなぁ、

簡単な感じでいいんだけど、、、。

と長いこと考えていてやっと重い腰を上げてとりかかってみました。

その時躓いたことなどをメモ。

htmlは弄らず(増やさず)CSSのみで対応したい

CMS(CMSをあまり理解していませんが、、、)など使用してなかったので

更新の度にPC用、スマホ用両方更新するのメンドクサイ。

とりえずCSSだけでどうにかしよう。

どうにかなるだろう。

とりあえずやってみたこと

  • 不要な画像、ナビゲーションをdisplay: none
  • 各セクションのdivのwidthを100%に
  • 消したいテキストはtext-indentで画像置き換え
  • リストのナビゲーションのアンカーをブロック要素に
  • nth-child(n)::afterでcontentを挿入


まずはがんがんdisplay: none;で画像やら不要なナビを非表示に。

なんて無駄が多いんだ。

body,div#header,div#main,div#footerなどのdivのwidthを100%に変更。

その際子のブロック要素にうっかりwidth: 100%を設定し、paddingを設定してしまうと

横スクロールが出てしまうのでご注意を。

そんで画像に置き換えたいテキストがあればCSSのtext-indentで画像置換え。

画像置換えは→[CSS]画像置換「-9999px」のパフォーマンスを改善した新しいテクニック

ヘッダー、フッターのナビをうまいこと必要な分だけ利用してなんとなくナビを作成。

リスト内アンカーをブロックにして入りきらいテキストは...表示にするため、

text-overflow、white-space、overflowを設定。

 ↓こんな感じでリストメニューはOK??
.navi li {
    width: 100%;
    border-bottom: solid 1px #ccc;
}
.navi li a {
    text-decoration: none;
    display: block;
    padding: 10px 20px 10px 10px;
    margin-right: 5px;
    background: url('../images/arrow.png') no-repeat right center;
    -webkit-background-size: 20px 20px;
    text-overflow: ellipsis;
    white-space: nowrap;
    overflow: hidden;
}


そして擬似要素before afterでコンテンツを挿入。

こんなんで大丈夫だろうかと思いつつも続行。

ボタンはCSS3 Button Generatoここで素敵なのが簡単に作れますね。

retina用にアイコンサイズは倍で作って

-webkit-background-size:これで半分表示に。

 予想外。意外とまとまった。

このCSSをどう読み込むか、ヘッド内でメディアクエリで読み込むか。

とも思ったけどjavascriptでユーザーエージェントで判別して

既存のCSSを書きかえることにしました。

PCサイト、スマートフォンサイトの切り替えをどうしよう。

ここ、悩みました。

とりあずの対応だったんですがなんとなくこの機能は譲れなっかたんです。

ヘッド内でメディアクエリで分岐したらPC表記への切り替えられても

ページ遷移したら戻っちゃうし。そもそも全html直したくないし。

普通はPHPとかでやるんですよね、きっと。

が、しかし、PHPよくわからなかったので、

javascriptのセッションストレージという便利なものがあったのでそれで対応。

以下自信ないですがコード。
(function() {
    // セッションストレージに対応してるか?
    if(typeof sessionStorage === 'undefined') return;
    
    var spFlag = false;
    var n = navigator.userAgent;
    var uap = new RegExp('iPhone|Android.+Mobile|iPod');
    //ユーザーエージェントにてスマホ判別
    if(n.match(uap)) {
        spFlag = true;
        //対応しててもプライベートブラウズだとエラーになってしまうので。
        try {
            //セッションスタートかどうかチェック
            //confirmはお好みで
            //if(sessionStorage['SPorPC'] == undefined) sessionStorage['SPorPC'] = confirm('スマートフォン用サイトを表示しますか?') ? 'sp' : 'pc';
            if(sessionStorage['SPorPC'] == undefined) sessionStorage['SPorPC'] = 'sp';
        } catch(e) {
            //プライベートブラウズ時、他ストレージエラー時はスマホフラグをfalseに
            spFlag = false;
        };
    };
    
    //PC、スマホ切り替えボタンにclickイベントをliveで紐付け
    $('#pc, #sp').live('click', function() {
        sessionStorage['SPorPC'] = this.id;
        scrollTo(0,0);
        //changeView();// no load
        location.reload();// reload
    });
    
    function changeView() {
        //スマホの時のみ呼ばれsessionStorageがPCかSPかを
        //判別してフラグを書き換えます。
        spFlag = !(sessionStorage['SPorPC'] == 'pc');
        
        //既存(PC用)のスタイルシートをデフォルトのままかスマホ用に書き換えてます。
        //全てのスタイルシートを書き換えてるので変更の無いCSSもスマホ用が必要になってしまいますが、、、。
        //下はスマホ用は頭に「sp_」を付けて正規表現でパスを書き換えています。
        var $path = $('link[rel="stylesheet"]');
        for(var i = 0,len = $path.length; i < len; i++) {
            $path[i].href = changePath($path[i].href);
        };
        
        function changePath(path) {
            //コピペするとこの正規表現のバックスラッシュがエラーになりますのでご注意を。
            var trim = path.match(/sp_[0-9a-z]+¥.css|[0-9a-z]+¥.css/);
            
            trim[1] = (spFlag) ? 'sp_' + trim[0] : trim[0].replace('sp_', '');
            var changedPath = path.replace(trim[0], trim[1]);
            return changedPath;
        };
        
        //viewportをheadに挿入
        if(spFlag) {
            var meta = '<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0" />';
            $('head').append(meta);
        } else if(!spFlag && n.indexOf('Android') != -1) {
            //AndroidはPCサイトに切り替えた際PC用のwidthをviewportに設定しないとdivice-widthのままになっているような気がします。
            var meta = '<meta name="viewport" content="width=980" />';
            $('head').append(meta);
        };
        
        $(function() {
            //スクロールしてURLバーを隠します
            scrollTo(0,1);
            //PCからスマホ、スマホからPCへの切り替えボタンを挿入。
            if(spFlag) {
                var btn = '<div id="spbtn"><a href="javascript:void(0);" class="btn" id="pc">PC</a></div>';
                $('h1').after(btn);
                
                var $switch = $('#switch');
                if($switch) $switch.remove();
            } else {
                var swt = '<div id="switch">表示切替 : <a href="javascript:void(0);" id="sp">スマートフォン</a></div>';
                $('#footer').after(swt);
                
                var $spbtn = $('#spbtn');
                if($spbtn) $spbtn.remove();
            };
        });
    };
    //スマホだったらchangeViewを実行
    if(spFlag) changeView();
    
})();


最初はリロードしないで表示を切り替えるつもりだったので色々無駄が多いです。

 ページをロードしないとどーもviewportがうまいこといきませんでした。

更にリロードしてもAndroidがどーもしっくりこなかったので

PCサイト用のwidthを入れてみたらまぁなんとか。

キャッシュなんですかね〜?

それでこれを全てのhtmlで読み込んでる共通のスクリプト(あればですが、、、)

に記述すればPC用表示にして他のページに移動してもPC表記のまま!

すぐぶちあたった欠点

なんといってもプライベートブラウズではwebストレージが使用できません!!

残念。

だけどChromeのシークレットモードはOKでした!

それとPC、SP切り替えをまたいでブラウザの戻るボタンで移動すると

キャッシュを読んでるためなんだかなぁ。って感じです。

それとAndroidのページ内移動(a href="#top"ってやつです)、

 これ一回しかできないんですね。

そんなこと思いもせず結構悩みました。

ここはjavascriptで対応するしかなさそうですね。

それと直接関係ないですがiPhoneはどうやらjQueryの

live関数と相性が悪いらしくイベントが登録されないみたいです。

JQueryのliveイベントがiPhoneのSafariで登録できない

確かにonclick属性を入れたらちゃんとイベントが実行されました。

上のコードの切り替えボタンは

javascript:void(0)あたりが効いてるのでしょうか?

一応動きます。

結論

viewport、特にAndroidがよくわかりません!

Androidが欲しい。

何かミスがありましたらご指摘いただけると嬉しいです。

1

calendar

S M T W T F S
      1
2345678
9101112131415
16171819202122
23242526272829
30      
<< September 2012 >>

profile

last entry:2013/06/10

selected entries

categories

archives

recent comment

search this site.

others