LoginSignup
25
25

More than 5 years have passed since last update.

WEBアプリ「Sun」を解析してみた

Last updated at Posted at 2013-08-19

ネイティブアプリのようなWEBアプリ「Sun」がどういう技術・方法で作られているか解析してみた。

読み込み時の挙動

sunはアクセスした環境別(PCブラウザ・モバイルブラウザ・WEBアプリモード)の画面が表示される。
※WEBアプリモードとはナビゲーションバーやアドレスバーの無い状態。

アクセス環境をチェック

まずwindow.navigator.standaloneでWEBアプリモードか否かを評価し、真の場合はWEBアプリモードの画面を表示する。
偽の場合はさらにユーザーエージェントを調べモバイルかPCかを評価して表示内容を切り替えている。

javascript
if (!window.navigator.standalone) {
    if (navigator.userAgent.match(/like Mac OS X/i)) {
        //モバイルブラウザ
    }else {
        //PCブラウザ
    }
}else {
    //WEBアプリモード
}

body内のHTMLを丸々差し替え

モバイルブラウザの場合とWEBアプリモードの場合はbody以下のHTMLを丸々差し替えている
PCブラウザの場合はそのまま表示。

javascript
//モバイルブラウザ
$('body').addClass('install').html('<div id="install"><div id="homescreen"><span></span><h2 id="add">Add to your <strong>Home Screen</strong></h2></div></div>');

//WEBアプリモード
$('body').removeClass('preview').addClass('initialize').html('<div id="app"><div id="box"><div id="layer"><div class="slide"><div class="background"></div><a class="in">In</a><div class="pagination"><span class="active"></span><span></span><span></span><span></span></div></div></div></div></div>');

オフラインの場合はお知らせを出す

javascript
if(!window.navigator.onLine) {
    $('.pagination').hide();
    $(document).bind('touchstart', function(e) {
        e.preventDefault();
    });
    notification("Sun requires a working 3G or WiFi connection.");
} else {
    //オンライン時の処理
}

座標を取得して天気情報を取得する

navigator.geolocationが使えない場合の処理は無いっぽい。

javascript
if (navigator.geolocation) {  
    navigator.geolocation.getCurrentPosition(
        function(position) {  
            var lat = position.coords.latitude;
            var lon = position.coords.longitude;

            $.ajax({ url:'http://maps.googleapis.com/maps/api/geocode/json?latlng='+lat+','+lon+'&sensor=true',
                    success: function(data){
                        //data使ってごにょごにょ
                    }
            });

        }
    );
}

アプリケーションキャッシュ

マニフェストファイル

マニフェストファイルによりほぼすべてのリソースがキャッシュされている。
が、NETWORKヘッダがアスタリスクなのですべてネットワークリソースにアクセスしている!?

text
CACHE MANIFEST
# Sun 2.1.0.5

NETWORK:
*

CACHE:
# style
resources/sun.css

# scripts
resources/library.js
resources/charts.js
resources/sunny.js

# images
resources/icon_adrift.png
resources/icon_envious.png
resources/icon_goldfish.png
resources/icon_jour.png
resources/icon_looper.png
resources/icon_moon.png
resources/icon_pastel.png
resources/icon_stardust.png
resources/icon@2x.jpg
resources/canvas.png
resources/canvas@2x.png
resources/ipad-landscape.png
resources/ipad-landscape@2x.png
resources/ipad-portrait.png
resources/ipad-portrait@2x.png
resources/iphone.png
resources/iphone5.png
resources/texture.jpg
resources/iphone.jpg
resources/iphone@2x.jpg

ローカルストレージ

以下の情報をローカルストレージで管理している

  • 都市情報(都市名・都市ID・座標情報)
  • テーマカラー
  • 摂氏 or 華氏(navigator.language == 'en-US'だと華氏)
  • 風速単位(m/s or mph)

3D表現を使った画面切り替え

rotate3dでY軸に対して回転して立方体の4面を作る

html
<div id="box">
    <div id="layer" style="-webkit-transform: translate3d(0px, 0px, -160px) rotate3d(0, 1, 0, 0deg);">
        <div class="slide" style="-webkit-transform: rotate3d(0, 1, 0, 0deg) translate3d(0px, 0px, 160px);">
            /* 要素 */
        </div>
        <div class="slide" style="-webkit-transform: rotate3d(0, 1, 0, 90deg) translate3d(0px, 0px, 160px);">
            /* 要素 */
        </div>
        <div class="slide" style="-webkit-transform: rotate3d(0, 1, 0, 180deg) translate3d(0px, 0px, 160px);">
            /* 要素 */
        </div>
        <div class ="slide" style="-webkit-transform: rotate3d(0, 1, 0, 270deg) translate3d(0px, 0px, 160px);">
            /* 要素 */
        </div>
    </div>
</div>

slide要素にtranslate3d(0, 0, 160px)している理由
translate3d(0, 0, 0)のままだと、それぞれの面が中心でかさなり四角形にならないため、それぞれ面の半分のpxだけオフセットしている。
ただしその分拡大して見えてしまうため、親ボックス(layer要素)にtranslate3d(0, 0, -160px)をいれて見た目を最適化している。

CSSで3D表現を指定する

layer要素にtransform-style: preserve-3d、その親のbox要素にperspective: 1200pxを指定する

css
#box {
    width: 100%;
    height: 100%;
    position: relative; 
    -webkit-perspective: 1200px; 
}
#layer {
    width: 100%; 
    height: 100%; 
    position: absolute; 
    -webkit-transform-style: preserve-3d; 
    -webkit-transition-property: -webkit-transform; 
    -webkit-transition-duration: 550ms; 
    -webkit-transition-timing-function: ease-out; 
    -webkit-transition-delay: initial;
    top: 0px; 
    left: 0px;
}

JSからlayer要素のrotate3dを変更して回転する

layer要素のrotate3dプロパティのZ軸を変更して回転している。
layer要素には-webkit-transition-property: -webkit-transformが設定されているので、回転アニメーションによって画面が切り替わる。

html
<div id="layer" style="-webkit-transform: translate3d(0px, 0px, -160px) rotate3d(0, 1, 0, -90deg);">

グラフ表現

highcharts.jsを使用して実装している
http://www.highcharts.com

javascript
var chartTemp = new Highcharts.Chart({
    //parameters
});

エリアスクロール

サイドメニュー&週間天気ともにoverflow: scrollを使っている
-webkit-overflow-scrolling: touch;を使ってスムーズなスクロールを実現している

HTMLのヘッダ

html
<!-- WEBアプリモードをONにする -->
<meta name="apple-mobile-web-app-capable" content="yes">
<!-- ステータスバーの表示を制御する -->
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<!-- ホームアイコン下に表示されるアプリタイトルを指定する -->
<meta name="apple-mobile-web-app-title" content="Sun" />
<!-- アプリを開いた時に表示される画像(スプラッシュ画像)をサイズ別に指定する -->
<link rel="apple-touch-startup-image" href="resources/iphone.png" />
<link rel="apple-touch-startup-image" href="resources/ipad-portrait.png" media="screen and (min-device-width: 481px) and (max-device-width: 1024px) and (orientation:portrait)" />
<link rel="apple-touch-startup-image" href="resources/ipad-landscape.png"  media="screen and (min-device-width: 481px) and (max-device-width: 1024px) and (orientation:landscape)" />
<link rel="apple-touch-startup-image" href="resources/ipad-portrait@2x.png" media="screen and (min-device-width: 481px) and (max-device-width: 1024px) and (orientation:portrait) and (-webkit-min-device-ixel-ratio: 2)" />
<link rel="apple-touch-startup-image" href="resources/ipad-landscape@2x.png" media="screen and (min-device-width: 481px) and (max-device-width: 1024px) and (orientation:landscape) and (-webkit-min-device-ixel-ratio: 2)" />
<link rel="apple-touch-startup-image" href="resources/iphone5.png" media="screen and (device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2)" />

雑感

普段WEBアプリモードの制作をしないので、WEBアプリの場合のメタ情報の書き方やデバイス毎の指定方法等、勉強になった。実際その機会が来た時に参考にしようと思う。
UI面だとスクロールがoverflow:scrollということが以外だった。
overflow:scrollだとタップしないとスクロールバーが出ないので、悪しき方法というイメージだったが、実際このアプリを使うと「スクロールできそうな場所」で使っているからか、迷うこと無くスクロールを使っていた。
今後エリアスクロールが必要な場面ではoverflow:scrollでもUI的に表現可能かを意識しようと思う。
追記:-webkit-overflow-scrolling: touch;が使えない環境ではスムーズなスクロールを実現できない。

25
25
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
25
25