スマートフォンサイトの入門書

先週末のjavascriptの読書会の懇親会で、スマートフォン用のサイトの話を聞いて、ネイティブアプリもwebアプリも作れるようになっとかなアカンなぁと勉強してみた。

本書はスマートフォンサイトを製作するには3つのアプローチがあって、本書では最初の二つを取り扱ってます。

  • 専用サイトをフルスクラッチで
  • PCサイトをCSS/Javascriptでスマートフォン用に見やすく
  • 携帯向けサイトを流用

全ページカラーで見やすいし、説明も丁寧なので入門書としてはオススメかと思う。小さい画面に対応するためにはというよりは、タッチパネルのような指で触るデバイスのインターフェースをどう設計するか、はまりどころはどこか?PC用のサイトとはどう違ってどういうところに気をつけるべきなのか?というあたりが知りたかったので本書は良かったですね。

ProductName iPhone+Android スマートフォンサイト制作入門 (WEB PROFESSIONAL)
たにぐちまこと
アスキー・メディアワークス / 2499円 ( 2011-02-19 )


個人的には1章は必要なくて、2章のCacooを利用した設計フローと4章の実践テクニックが役に立った。

  • HTML5用のリセットCSS
  • webclipアイコンは57x57px

基本的なところを押さえたらjQuery Mobileを使っていけばいいのかな。

FlaskとXDMつかってgooglemapとtwitterを連動させるサンプル

HTML5 APIガイドブック コミュニケーション系API編が面白い。ひと通り読んだので、コード書いてみてる。

2章のサンプルコードをFlaskで。サンプルコードは3つのHTMLファイルが必要だけどFlask使えば一つのファイルに全部押し込めるので管理が楽。

gmap2twitter

初期値は富士市役所のあたりから半径5キロ以内のtweetを探すようにした。で地図をドラッグすると、それに伴いtweetも連動して表示されるので、ほーこんなユーザーいるのか!と新たな発見もあった。

この本は入門書として最適かもしれん。

ProductName 徹底解説 HTML5 APIガイドブック コミュニケーション系API編
小松 健作
秀和システム / 2730円 ( 2010-12 )


Flaskコード

#!/usr/bin/env python
# -*- encoding:utf-8 -*-

from flask import Flask

app = Flask(__name__)

@app.route("/")
def processing():
    response = """
<!doctype html>
<html lnag=ja>
<head>
<meta charset="utf-8">
<style type="text/css">
.page { margin: 0px auto; border: 0px; padding: 0px; text-align: center;}
</style>
</head>
<body>
<div class=page>
<h1>gmap2tweet</h1>
<iframe src="/googlemap" id=gmap width="500px" height="500px"></iframe>
<iframe src="/twitter" id=twitter width="500px" height="500px"></iframe>
<div id=mesg></div>
</div>
<script>
  var initialize = function(){
    var origin = location.protocol + "//" + location.host;
    var iframes = document.querySelectorAll('iframe');

    for(var i = 0; i < iframes.length; i++){
      iframes[i].contentWindow.postMessage('init', origin);
    }

    window.addEventListener('message', function(e){
        if (e.origin == origin) {
          document.getElementById('mesg').innerHTML = "receive data via xdm::" + e.data;
          document.getElementById('twitter').contentWindow.postMessage(e.data, origin);
        }
    }, false);
  }
  window.onload = function(){ initialize(); }
</script>
</body>
</html>
"""
    return response

@app.route("/twitter")
def twitter_processing():
    response = """
<!doctype html>
<html lang=ja>
<head>
<meta charset="utf-8">
</head>
<body>
<div id=mesg></div>
<div id=results></div>
<script>
var origin = location.protocol+"//"+location.host;
var parentWin = null;
var api="http://search.twitter.com/search.json?callback=show&rpp=50&geocode=";
var jsonpObj =null;

var sendJsonp = function(latlng, radius){
  if(jsonpObj)
    document.body.removeChild(jsonpObj);
  var scr = document.createElement('script');
  scr.src = api+encodeURIComponent(latlng+","+radius+"km");
  scr.type = "text/javascript";
  jsonpObj = document.body.appendChild(scr);
};

var show = function(obj){
  var results = obj.results;
  var out = '';
  var template = '<img src="#{img}"> <a href="http://twitter.com/\
#{from_user}" target="_blank"><b>#{from_user}</b></a> #{text}<br />\
#{created_at}<hr />';

  for(var i = 0; i < results.length; i++){
    var res = results[i];
    var tmp = template.replace("#{img}", res.profile_image_url) \
.replace("#{from_user}", res.from_user) \
.replace("#{from_user}", res.from_user);
    tmp = tmp.replace("#{text}", res.text) \
.replace("#{created_at}", res.created_at);
    out += tmp;
  }

  document.getElementById('results').innerHTML = out;
};

window.addEventListener('message', function(e){
  if(e.origin == origin) {
    if (e.data == 'init') {
      parentWin = e.source;
    } else {
      document.getElementById('mesg').innerHTML = e.data;
      document.getElementById('results').innerHTML = "読み込み中";
      sendJsonp(e.data, 5);
    }
  }
}, false);
</script>
</body>
</html>
"""
    return response

@app.route("/googlemap")
def google_processing():
    response = """
<!doctype html>
<html lang=ja>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
</head>
<body style="padding:0;margin:0;height:500px">
<div id=map_canvas style="width: 100%; height: 100%; border: 0px"></div>

<script>
var parentWin = null;
var origin = location.protocol + "//" + location.host;

var start = function() {
  var latlng = new google.maps.LatLng(35.164190, 138.678609);
  var myOptions = {zoom: 13, center: latlng, mapTypeId: google.maps.MapTypeId.ROADMAP};

  var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);

  var getCenter = function(){
    var center = map.getCenter();
    var lat = center.lat(); 
    var lng = center.lng();
    if(parentWin) {
      parentWin.postMessage(lat+","+lng, origin);
    }
  };

  window.addEventListener('message', function(e){
    if(e.origin == origin) {
      if(e.data == 'init') {
        parentWin = e.source;
        getCenter();
      }
    } else {
      alert("illegal message from " + e.origin);
    }
  }, false);

  google.maps.event.addListener(map, 'dragend', function(e){getCenter();});
  google.maps.event.addListener(map, 'zoom_changed', function(e){getCenter();});

};

window.onload = function(){start();};
</script>
</body>
</html>
"""
    return response

if __name__ == "__main__":
    app.run()

javascriptの対話環境を入れた

昔、jsっていう対話環境入れてた気がするんだけど、覚えてないのでv8のやつをおもむろに入れてみたという話。

sconsを入れるために

sudo port install scons

って打ったら、opensslは入れるわ、pythonのバージョン上げるわでやたら時間がかかった。

scons入れたら

svn checkout http://v8.googlecode.com/svn/trunk/ v8
cd v8
scons
scons sample=shell

で対話環境が手に入る。

$ ./shell
V8 version 3.0.6.1
> (function (x,y){return x+y})(3,4)
7

ついでにnode.jsも入れた

wget http://nodejs.org/dist/node-v0.2.6.tar.gz
tar xvfz node-v0.2.6.tar.gz
cd node-v0.2.6
./configure
make
sudo make install

ProductName 徹底解説 HTML5 APIガイドブック コミュニケーション系API編
小松 健作
秀和システム / 2730円 ( 2010-12 )


javascript+canvas

canvas-tetrisのソースを眺めながら、5x5の格子の色をランダムに変えてみた。sでスタートとストップを交互に繰り返す

canvas-test

整数の乱数値を取りたい時にはrandomしてfloorする

Math.floor(Math.random() * 255)

ループさせたい場合にはsetIntervalで止めたい時にはclearInterval。この例ではrunning = !runningでトグルさせてる。

if( running ){
  clearInterval( drawLoop )
  var r = Math.floor(Math.random() * 255);
  alert("stopped ");
}else{
  drawLoop = setInterval(drawMap, 50);
}
running = !running;

以下、全コード


<!DOCTYPE html>
<html>
<head>
  <title>Canvas Test</head>
</head>
<body>
  <h1 style='text-align:center'>Canvas Test</h1>
  <div style='text-align:center'>
    <canvas id='game' style='border:solid 2px #aaa;'>
      Your browser does not support the &lt;canvas&gt; element.<br>
      Please use a normal browser. Hint: Safari, Chrome, Firefox.
    </canvas>
  </div>
<script type="text/javascript" charset="utf-8">
  var SQ      = 25;   // square side in pixels
  var HCOUNT  = 5;   // horizontal width in squares
  var VCOUNT  = 5;   // vertical width in squares
  var WIDTH   = SQ * HCOUNT;
  var HEIGHT  = SQ * VCOUNT;
  var BGCOLOR = '#fff';
  var canvas = document.getElementById('game');
  canvas.width = WIDTH;
  canvas.height = HEIGHT;

  var ctx = canvas.getContext('2d');

  function line( fromx, fromy, tox, toy ){
    ctx.beginPath();
    ctx.moveTo( fromx, fromy );
    ctx.lineTo( tox, toy );
    ctx.stroke();
  }

  ctx.strokeStyle = '#999';
  ctx.lineWidth = .5;

  function drawMap() {
    // clear map and draw grid
    ctx.clearRect( 0, 0, WIDTH, HEIGHT );
    var currentSquare, w, h, i;

    // this loop draws the current map state
    for( w = 0; w < HCOUNT; w++ ){
      ctx.save();
      ctx.translate( w * SQ, 0 ); // Move the canvas horizontally
      for( h = 0; h < VCOUNT; h++ ){
        ctx.save();
        ctx.translate( 0, h * SQ ); // Move the canvas vertically
        var r = Math.floor(Math.random() * 255);
        var g = Math.floor(Math.random() * 255);
    var b = Math.floor(Math.random() * 255);
    ctx.fillStyle = "rgb("+r+","+g+","+b+")";
        ctx.fillRect( 0, 0, SQ, SQ );
        ctx.restore();
      }
      ctx.restore();
    }

    for( i = 1; i < WIDTH; i++ )
      line( i*SQ, 0, i*SQ, HEIGHT );
    for( i = 1; i < HEIGHT; i++ )
      line( 0, i*SQ, WIDTH, i*SQ );
  }

  var running = false, drawLoop;

  document.onkeydown = function(e) {
    var key = e.which;    

    if( key === 83 ) { // s - stop (pause)
      if( running ){
        clearInterval( drawLoop )
        var r = Math.floor(Math.random() * 255);
        alert("stopped ");
      }
      else{
        drawLoop = setInterval(drawMap, 50);
      }
      running = !running;
    }    
  }
</script>
</body>
</html>

「Google API Expertが解説するHTML5ガイドブック」を読んだ

5章のほかに7,8,9も興味があったのだけど、7,8,9は内容が薄いというかサンプルがそそられなかった。一応押さえておけば、なんかすごい例が出てきたときにすぐに取り入れられていいのかも。

あと、ありがちなデザイナー向けな本ではなくてプログラマー向けなのでよかったが、そのわりにはプログラマー向けの記述、例えばCommetとWebsocketってどう違うのよ?とかそういうあたりがちょっとしか触れられてなくて、どこがどう違ってどういう利点があるのよとかそういうことが知りたかった。あとWeb Workers 8pageって端折り過ぎじゃね?

ProductName Google API Expertが解説するHTML5ガイドブック
羽田野 太巳,白石 俊平,古籏 一浩,太田 昌吾
インプレスジャパン / ¥ 2,940 ()
在庫あり。

  • 第1章 イントロダクション [羽田野 太巳]
  • 第2章 Canvas [羽田野 太巳]
  • 第3章 SVG [太田 昌吾]
  • 第4章 Video & Audio [古籏 一浩]
  • 第5章 ドラッグ&ドロップ [羽田野 太巳]
  • 第6章 オフラインWebアプリケーション [白石 俊平]
  • 第7章 WebSocket [白石 俊平]
  • 第8章 Web Workers [白石 俊平]
  • 第9章 Geolocation [古籏 一浩]

ドラッグアンドドロップのサンプルは実際にやってみた。これはいい。

drag and drop sample

HTML5

HTML5ROCKSというサイトのプレゼンテーションを見ていて、オースゲー!ってなった。

で、スライド

HTML5 ~= HTML  + CSS  + JS APIs

って書いてあったのでそんな感じの書籍を探してみた。

なか見検索によるとこれはマークアップ主体らしい

ProductName 徹底解説HTML5マークアップガイドブック
羽田野太巳
秀和システム / ¥ 3,150 ()
在庫あり。

一方、こちらはレビューによるとW3Cのドラフトについて主にJavaScript部分を和訳したとのことなのでJSの内容らしいが、ちょっと辛口の評価が気になるので立ち読みしてから検討しよう。HTML5ROCKS読んでから。

ProductName HTML5&API入門
白石 俊平
日経BP社 / ¥ 2,940 ()
在庫あり。

残るは8月にでるらしい洋書

ProductName Beginning HTML5 and CSS3: Next Generation Web Standards
Christopher Murphy,Richard Clark,Oli Studholme
Apress / ¥ 3,852 ()
近日発売 予約可

  • Cutting-edge web development techniques with HTML5 and CSS3
  • The new features of HTML5 and how to work with HTML5 and CSS3
  • The new web standards being implemented by all the major web browsers
  • How to work with the new HTML5 structural sections
  • How to create HTML5 and CSS3 layouts
  • How to create transitions and animations without using Flash
  • New web typography solutions
  • A new vision of web development with HTML5 and CSS3

洋書でも買ってみるかな。