@blog.justoneplanet.info

日々勉強

svgをやりたいからRaphaëlを使ってみる

実践あるのみ。o(^O^*=*^O^)oでも面倒だからjQueryを使用する。

■円を描く

JavaScript

$(function(){
    // 描画エリアをidで指定
    var paper = Raphael("notepad", 320, 50);
    // 円を描く
    var circle = paper.circle(20, 20, 10);
});

HTML

<div id="notepad"></div>

サンプル

おー。できた(*^-^)

■パスを描く

JavaScript

$(function(){
    // 描画エリアをidで指定
    var paper = Raphael("notepad", 320, 200);
    // パスを描く
    var path = paper.path("M25 25L20 65L25 105L65 110L105 105L110 65L105 25L75 20L45 25L40 55L45 85L65 90L85 85L90 65L85 45L75 40L65 45L60 55L65 65");
});

サンプル

ふむふむ。分かってきた。パスの書き方を見てみると相対的でも座標を指定できるらしい。

■文字を描く

JavaScript

$(function(){
    // 描画エリアをidで指定
    var paper = Raphael("notepad", 320, 30);
    // 文字を描く
    var string = paper.text (90, 10, "なめらかなベクターグラフィックス。\nSVGです。");
});

サンプル

おー。どうやらセンタリングされるらしいな★

■ドラッグ&ドロップしてみる

JavaScript

$(function(){
    var paper = Raphael("notepad", 500, 100);
    var circle = paper.circle(50, 40, 10);
    circle.attr("fill", "#55ccff");
    circle.attr("stroke", "#55ccff");
    circle.drag(
        function(dx, dy){// move
            this.attr({
                "cx" : this.ox + dx,
                "cy" : this.oy + dy
            });
        },
        function(){// start
            this.ox = this.attr("cx");
            this.oy = this.attr("cy");
            this.attr({"opacity" : 0.5});
        },
        function(){// end
            this.attr({"opacity" : 1});
        }
    );
});

サンプル

おー。キター(゜∀゜)

■DOM

DOMが取り出せるらしいぞ!

JavaScript

$(function(){
    var paper = Raphael("notepad", 320, 50);
    var circle = paper.circle(20, 20, 10);
    circle.attr('fill', 'blue');
    circle.node.onclick = function(){
        alert('hello!');
    }
});

サンプル

jQueryと組み合わせは・・・

$(function(){
    var paper = Raphael("notepad", 320, 50);
    var circle = paper.circle(20, 20, 10);
    circle.attr('fill', 'blue');
    $(circle.node).click(function(){
        alert('hello!');
    });
});

サンプル

むはっ★

$(function(){
    var paper = Raphael("notepad", 320, 50);
    var circle = paper.circle(20, 20, 10);
    circle.attr('fill', 'blue');
    $(circle.node).click(function(){
        circle.hide();
    });
});

サンプル

■参考

Raphael Reference

html5を使う準備をする

■準備

DOCTYPE宣言

以下のように記述する。

<!DOCTYPE html>

エンコード

以下のように記述する。

<meta charset="UTF-8" />

もしくは以下のように記述する。

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

どっちかだけ書くように(o^-‘)b

■時代遅れのブラウザで使う準備

block要素として認識してほしいものをcssで指定。

section,
header,
footer,
nav,
aside,
article,
address,
figure,
hgroup,
menu {
    display: block;
}
[hidden],
menu[type="context"],
command,
datalist,
rp,
source {
    display: none;
}

IE6~8

面倒なので以下のスクリプトを書いて終わりにする。m(。・ε・。)m

<!--[if lt IE 9]>
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->

中身が気になる。「(゚ペ)

// html5shiv MIT @rem remysharp.com/html5-enabling-script
// iepp v1.5.1 MIT @jon_neal iecss.com/print-protector
(function (p, e)
{
    var q = e.createElement("div");
    q.innerHTML = "<z>i</z>";
    q.childNodes.length !== 1 && function ()
    {
        function r(a, b)
        {
            if (g[a]) {
                g[a].styleSheet.cssText += b;
            }
            else {
                var c = s[l], d = e[j]("style");
                d.media = a;
                c.insertBefore(d, c[l]);
                g[a] = d;
                r(a, b)
            }
        }
        function t(a, b)
        {
            for (var c = new RegExp("\\b(" + m + ")\\b(?!.*[;}])", "gi"), d = function (k)
            {
                return ".iepp_" + k;
            },
            h =- 1;
            ++h < a.length;
            ) {
                b = a[h].media || b;
                t(a[h].imports, b);
                r(b, a[h].cssText.replace(c, d))
            }
        }
        for (var s = e.documentElement, i = e.createDocumentFragment(), g = {}, m = "abbr article aside audio canvas details figcaption figure footer header hgroup mark meter nav output progress section summary time video".replace(/ /g, 
        '|'), n = m.split("|"), f = [], o =- 1, l = "firstChild", j = "createElement";
        ++o < n.length;
        ) {
            e[j](n[o]);
            i[j](n[o])
        }
        i = i.appendChild(e[j]("div"));
        p.attachEvent("onbeforeprint", function ()
        {
            for (var a, b = e.getElementsByTagName("*"), c, d, h = new RegExp("^" + m + "$", "i"), k =- 1; ++k < b.length; )
            {
                if ((a = b[k]) && (d = a.nodeName.match(h))) 
                {
                    c = new RegExp("^\\s*<" + d + "(.*)\\/" + d + ">\\s*$", "i");
                    i.innerHTML = a.outerHTML.replace(/\r|\n/g, " ").replace(c, a.currentStyle.display == "block" ? "<div$1/div>" : "<span$1/span>");
                    c = i.childNodes[0];
                    c.className += " iepp_" + d;
                    c = f[f.length] = [a, c];
                    a.parentNode.replaceChild(c[1], c[0]) 
                }
                t(e.styleSheets, "all");
            }
        });
        p.attachEvent("onafterprint", function ()
        {
            for (var a =- 1, b; ++a < f.length; ) {
                f[a][1].parentNode.replaceChild(f[a][0], f[a][1]);
            }
            for (b in g) {
                s[l].removeChild(g[b]);
            }
            g = {};
            f = [];
        })
    }
    ()
})(this, document);

古いIEって大変だね。ヾ(・・;)

■その他

  • タグは省略できるが、個人的にはチャント書く。
  • 場合によっては無くても良いが、個人的に属性値はチャント”で括る。

バリデート

こいつを使う。o(^o^)o

新要素

ほんの一部をピックアップ。

section 文章のアウトライン
header セクションのヘッダー
footer セクションのフッター
nav 外側のセクションに対するナビゲーション
aside 外側のセクションに対する補足情報
article セクションみたいな感じで、独立したコンテンツ
hgroup h1~h6をまとめる
menu コマンドのリスト
figure キャプションとセットの要素を埋め込む際に使用
video 動画
audio 音声
source videoやaudioで使う
canvas キャンバス

もっともっとFile APIを使ってサーバ側で受け取ってみる

前回の記事に以下の質問がありました。

質問なのですがバイナリデータはsendでは送れないのでは?
自分も同じようなことをしているのですがFireFox限定のsendAsBinaryでないと無理でした。
どのようにして転送してるのでしょうか?

えーと。。。(・Θ・;)。。。あの、その。。。うかれててサーバ側を考えてませんでした。すみませんm(_ _)m

■クライアント側のコード

前回のコードとおなじ。

function dragStart(e){
    //e.preventDefault();
}
function dragEnter(e){
    //e.preventDefault();
}
function dragOver(e){
    e.preventDefault();
}
function drop(e){
    var files = e.dataTransfer.files;
    for(var i = 0; i < files.length; i++){
        var request = new XMLHttpRequest();
        request.upload.onprogress = function(e){
            document.getElementById('progress').style.width = ((e.loaded / e.total) * 100 + "%");
        }
        request.upload.onload = function(e){
            document.getElementById('progress').style.width = '0px';
            alert('finished');
        }
        request.open('post', "./index.html");
        request.send(files[i]);
    }
    e.preventDefault();
}

サーバー側

今回のケースは、$_FILESなどでファイルを取得することはできない。以下のようにして生のPOSTデータを取得しなければならない。

$post = fopen("php://input", "r");
file_put_contents('./test.png', $post);//ファイル名はテストなので固定=3
fclose($post);

ちゃんと受け取れるヽ(^◇^*)/。簡易的なコードなので実環境ではフィルタリングしてください。

■sendAsBinaryとsendを比較して使ってみる

以下はsendAsBinaryを使ったサンプルである。

request.open('post', "./index.html");
request.sendAsBinary(files[i].getAsBinary());

上述のコードが以下のコードに対応する。

request.open('post', "./index.html");
request.send(files[i]);

まとめ

  1. 引数がFileオブジェクトの時はsendを使用する
  2. 引数がBinary文字列の時はsendAsBinaryを使用する
  3. 引数がBinary文字列の時にsendを使用すると途中でデータがカットされてしまう

なるほど!

sendAsBinaryとは

A variant of the send() method that sends binary data.

sendAsBinaryはsendメソッドの変異体らしい。

This data is converted to a string of single-byte characters by truncation (removing the high-order byte of each character).

シングルバイト文字列に変換されるらしい。

$_FILESで受け取りたい時

以下のようにsendAsBinaryを使用する。

request.open('post', "./index.php", true);
var boundary = '------multipartformboundary1276452374015';
request.setRequestHeader(
    'content-type',
    'multipart/form-data; boundary=' + boundary
);
request.setRequestHeader(
    'content-length',
    files[i].size
);
request.sendAsBinary(
    '--' + boundary + '\n' +
    'Content-Disposition: form-data; name="file"; filename="test.png"\n\n' +
    'Content-Type: application/octet-stream\n\n' +
    files[i].getAsBinary() + '\n' +
    '--' + boundary + '--'
);

以下のようにsendAsBinaryを使用する。ちなみにboundaryとは

マルチパートのデータは、この例のように「境界(boundary)」となる行でデータ項目が区切られ、それぞれがContent-Dispositionという説明情報などのあとに実際のデータが続くという形を取ります。

とのことである。

PHPでは以下のように受け取れる。

var_dump($_FILES);
/*
array(1) {
  ["file"]=>
  array(5) {
    ["name"]=>
    string(8) "test.png"
    ["type"]=>
    string(0) ""
    ["tmp_name"]=>
    string(14) "/tmp/sdhfhsg"
    ["error"]=>
    int(0)
    ["size"]=>
    int(10)
  }
}
*/
参考

勉強になったー=3

もっとFile APIを使ってXMLHttpRequestと組み合わせてみる

XMLHttpRequest Level2ではバイナリデータもアップロードできるようになった!ヽ(=´▽`=)ノ

■ソース

基本的には前回と同じコードを利用している。

<p ondragstart="dragstart(event)" ondragenter="dragenter(event);" ondragover="dragover(event);" ondrop="drop(event);">You drop some images, here!</p>
<div id="preview"></div>

次にJavaScriptコード。

function dragStart(e){
    //e.preventDefault();
}
function dragEnter(e){
    //e.preventDefault();
}
function dragOver(e){
    e.preventDefault();
}
function drop(e){
    var files = e.dataTransfer.files;
    for(var i = 0; i < files.length; i++){
        var request = new XMLHttpRequest();
        request.upload.onprogress = function(e){
            document.getElementById('progress').style.width = ((e.loaded / e.total) * 100 + "%");
        }
        request.upload.onload = function(e){
            document.getElementById('progress').style.width = '0px';
            alert('finished');
        }
        request.open('post', "./index.html");
        request.send(files[i]);
    }
    e.preventDefault();
}

ファイルアップロード部分

onprogressで進捗を把握できる。e.loadedはアップロードを行った容量で、e.totalは全体のアップロード容量である。

var request = new XMLHttpRequest();
request.upload.onprogress = function(e){
    document.getElementById('progress').style.width = ((e.loaded / e.total) * 100 + "%");
}

onload でアップロードの完了を取得できる。

request.upload.onload = function(e){
    document.getElementById('progress').style.width = '0px';
    alert('finished');
}
request.open('post', "./index.html");
request.send(files[i]);

Chromeについて

You can work around this by uploading the file via xmlhttprequest, maybe. I don’t
think Chrome has yet implemented the necessary HTML5 APIs for doing this yet,
unfortunately (they’re called FileStreams I think).

まだサポートしていないんじゃないか?と言ってるみたいだ。

WorkersからのDatabaseへのアクセスや,File API,XMLHttpRequestのFormData送信サポートなどはChrome 5での対応からChrome 6への対応に先送りされています

やっぱりFile APIへの対応はChrome6以降になったらしい。残念。

Web Platform Status

マイルストーン6で対応ですな=3

■サンプル

Firefox3.6以降でないと動かないですが、10MB以下のファイルを点線の中にドロップしてください。

You drop some files, here!

おまけ

jQuery1.4.2のbindを使うと、eventオブジェクトのプロパティdataTransferは、コールバック関数の引数のeventオブジェクトでは受け取れないようだ。従って、以下のコードは使えない。

$(elm).bind(
    'drop',
    function(e){
        e.preventDefault();
        var files = e.dataTransfer.files;
        for(var i = 0; i < files.length; i++){
            var request = new XMLHttpRequest();
            request.upload.onprogress = function(e){
                document.getElementById('progress').style.width = ((e.loaded / e.total) * 100 + "%");
            }
            request.upload.onload = function(e){
                document.getElementById('progress').style.width = '0px';
                alert('finished');
            }
            request.open('post', "./index.html");
            request.send(files[i]);
        }
        e.preventDefault();
    }
);

以下のようにaddEventListenerを使用すれば良い。

elm.addEventListener(
    'drop',
    function(e){
        e.preventDefault();
        var files = e.dataTransfer.files;
        for(var i = 0; i < files.length; i++){
            var request = new XMLHttpRequest();
            request.upload.onprogress = function(e){
                document.getElementById('progress').style.width = ((e.loaded / e.total) * 100 + "%");
            }
            request.upload.onload = function(e){
                document.getElementById('progress').style.width = '0px';
                alert('finished');
            }
            request.open('post', "./index.html");
            request.send(files[i]);
        }
        e.preventDefault();
    },
    false
);

さらにdropだけでなく、input type=”file”のchangeにもハンドリング可能だ。

elm.addEventListener(
    'change',
    function(e){
        e.preventDefault();
        var files = e.dataTransfer.files;
        for(var i = 0; i < files.length; i++){
            var request = new XMLHttpRequest();
            request.upload.onprogress = function(e){
                document.getElementById('progress').style.width = ((e.loaded / e.total) * 100 + "%");
            }
            request.upload.onload = function(e){
                document.getElementById('progress').style.width = '0px';
                alert('finished');
            }
            request.open('post', "./index.html");
            request.send(files[i]);
        }
        e.preventDefault();
    },
    false
);

File APIとドラッグ&ドロップを組み合わせてみる

HTML5では、ユーザが選択したファイルにJavaScriptからアクセスできるようになったヽ(*゚▽゚)ノ

■ソース

イベントハンドラが気に入らないけどまぁ。

<p ondragstart="dragstart(event)" ondragenter="dragenter(event);" ondragover="dragover(event);" ondrop="drop(event);">You drop some images, here!</p>
<div id="preview"></div>

JavaScript

グローバルに書くのが気に入らないけどまぁ。基本的な動作としてブラウザにファイルがドロップされるとブラウザはファイルを元の動作で処理しようとする。つまりJavaScriptに処理を渡すようにはなっていないので、e.preventDefault()でデフォルトのイベントを実行させないようにする。

function dragStart(e){
    //e.preventDefault();
}
function dragEnter(e){
    //e.preventDefault();
}
function dragOver(e){
    e.preventDefault();
}
function drop(e){
    var files = e.dataTransfer.files;
    for(var i = 0; i < files.length; i++){
        if(files[i].type.match(/image\/[a-z]/i)){
            var reader = new FileReader();
            var img = document.createElement('img');
            img.src   = reader.result;
            img.width = 300;
            document.getElementById('preview').appendChild(img);
            reader.onloadend = (function(img){
                return function(e){
                    img.src = e.target.result;
                }
            })(img);
            reader.readAsDataURL(files[i]);
        }
    }
    e.preventDefault();
}

Firefoxで動作確認。

Chromeについて

まだファイルの内容を読み込んだりは出来ないらしい

Chrome has partial support for this. In the test file I’ve attached, I can select a
file via the “Choose File” button and get metadata about it: its name, size and
type. However, I cannot read the contents of the file.

「部分的にサポートしているが内容の読み込みは出来ない」とのこと。まぁ、そのうち。

■サンプル

画像ファイルを点線の中にドロップしてください。

You drop some images, here!

リッチテキスト編集用APIを使ってみる

HTML5ではtinyMCEのような事が簡単にできる。

■編集

まずは以下のようにする。

<div contenteditable="true">編集</div>

サンプル

ただのp要素なのに、文字を入れたり、編集できますよー

<body contenteditable="true">
<p>編集</p>
</div>

上述のようにbodyに対しても可能である。

■装飾

以下のようにすると、編集可能領域において選択範囲を太字にできる。

document.execCommand('bold', false, false);

サンプル


ただのp要素なのに、文字を入れたり、編集できますよー

canvasを使用する

■HTML

以下のようにcanvas要素を置く。

<canvas id="canvas" width="500" height="500"></canvas>

widthとheightの指定には属性を使用する。

■JavaScript

canvasを使う準備。

var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');

円を書いてみる。

context.beginPath();
context.fillStyle = 'red';
context.arc(20, 20, 10, 0, Math.PI * 2, false);
context.fill();
context.closePath();

以下のようになる。


四角形を書く。

context.strokeRect(10, 20, 10, 20);
context.fillStyle = 'red';
context.fillRect(50, 20, 10, 20);

以下のようになる。


ちなみにpathではないのでbeginPath()は不要らしい。

線を書いてみる。

以下のようになる。

context.beginPath();
context.moveTo(0, 0);
context.lineTo(100, 20);
context.stroke();

味気ない。味気ない。


曲線を書いてみる。

以下のようになる。

context.beginPath();
context.moveTo(0, 0);
context.quadraticCurveTo(500, 20, 300, 50);
context.stroke();

第一引数と第二引数で引っ張るイメージだ。


microformat

検索のリッチ化が進む中、GoogleはRDFaとmicroformatに対応した。RDFaやmicroformatが埋め込まれたサイトでは検索結果が以下のように表示される。

リッチスニペット

■hCard(vCard)

人物に関する情報を記述する。

<div class="vcard">
<img class="photo" src="/wp-content/uploads/2009/12/1261861644_user_48.png" />
<p><strong class="fn">Mitsuaki Sample</strong></p>
<p><span class="org">Nutex Inc.</span>:<span class="title">Engineer</span></p>
<p><span class="adr">
<span class="postcode">141-0022</span><br />
<span class="region">東京都</span><span class="locality">品川区</span>
<span class="street-address">東五反田2-8-8</span><br />
</span></p>
</div>
name(fn) 名前
photo 写真
url URL
org 組織
title 役職
role 役割
adr 住所
>postcode 郵便番号
>region 都道府県
>locality 市町村
>street-address 番地

サンプル

Mitsuaki Sample

Nutex Inc.:Programmer

1410022
東京都品川区東五反田2-8-8

会社(組織情報)だと以下のようになる。

<div class="vcard">
<dt><span class="fn org">株式会社Nutex</span></dt>
<dd><span class="url">http://nutex.jp</span></dd>
<dd><span class="tel">03-5422-8684</span></dd>
<dd class="adr"><span class="postal-code">141-0022</span><br />
<span class="region">東京都</span><span class="locality">品川区</span><span class="street-address">東五反田2-8-8</span></dd>
</div>

サンプル

株式会社Nutex
http://nutex.jp
03-5422-8684
141-0022
東京都品川区東五反田2-8-8

■hReview

レビュー情報を記述する。

<div class="hreview">
<p><span class="item"><strong><span class="fn">NutexのCMS</span></strong></span> - Score:<strong><span class="rating">4.0</span></strong></p>
<p><span class="summary">凄く使いやすい。</span></p>
<p>written by <span class="reviewer">Mitsuaki Sample</span>(<span class="dtreviewed">2009-12-20</span>)</p>
</div>
item 対象アイテム
>name(fn) 名前
rating 評価点
reviewer 評価した人
dtreviewed 評価した日時
summary レビュー概要
description レビュー本文

サンプル

NutexのCMS – Score:4.0

凄く使いやすい。

written by Mitsuaki Sample(2009-12-20)

■hProduct

製品情報を記述する。

<div class="hproduct">
<h5><span class="fn">Rabit</span>(<span class="url">http://nutex.jp</span>)</h5>
<p><span class="price">\100</span></p>
<p class="ta-center"><span class="photo"><img src="http://blog.justoneplanet.info/wp-content/uploads/2009/12/1261863826_computer.png" alt="cms" width="128" height="128" /></span></p>
<p><span class="description">簡単CMS。</span></p>
<p>Brand: <span class="brand">Nutex</span> - Category: <span class="category">CMS</span></p>
</div>
name(fn) 製品名
price 値段
photo 製品写真
url 製品ページ
description 製品説明
brand ブランド
category カテゴリ

サンプル

Rabit(http://nutex.jp)

\100

cms

簡単CMS。

Brand: Nutex – Category: CMS

■応用

レビュー情報と製品情報を組み合わせる。

<div class="hreview">
<div class="item hproduct">
<h5><span class="fn">Rabit</span>(<span class="url">http://nutex.jp</span>)</h5>
<p><span class="price">\100</span></p>
<p class="ta-center"><span class="photo"><img src="http://blog.justoneplanet.info/wp-content/uploads/2009/12/1261863826_computer.png" alt="cms" width="128" height="128" /></span></p>
<p><span class="description">簡単CMS。</span></p>
<p>Brand: <span class="brand">Nutex</span> - Category: <span class="category">CMS</span></p>
</div>
<p><span class="summary">凄く使いやすい。</span> - Score:<strong><span class="rating">4.0</span></strong></p>
<p>written by <span class="reviewer">Mitsuaki Sample</span>(<span class="dtreviewed">2009-12-20</span>)</p>
</div>

サンプル

Rabit(http://nutex.jp)

\100

cms

簡単CMS。

Brand: Nutex – Category: CMS

凄く使いやすい。 – Score:4.0

written by Mitsuaki Sample(2009-12-20)

参考

チェックボックスの使い方

以下のコードよりも

<ul>
<li><input type="checkbox" name="check[]" value="1" />1</li>
<li><input type="checkbox" name="check[]" value="2" />2</li>
<li><input type="checkbox" name="check[]" value="3" />3</li>
<li><input type="checkbox" name="check[]" value="4" />4</li>
<li><input type="checkbox" name="check[]" value="5" />5</li>
</ul>
array(1) {
  ["check"]=>
  array(2) {
    [0]=>
    string(1) "2"
    [1]=>
    string(1) "4"
  }
}

以下のコードの方が

<ul>
<li><input type="checkbox" name="check[1]" value="1" />1</li>
<li><input type="checkbox" name="check[2]" value="1" />2</li>
<li><input type="checkbox" name="check[3]" value="1" />3</li>
<li><input type="checkbox" name="check[4]" value="1" />4</li>
<li><input type="checkbox" name="check[5]" value="1" />5</li>
</ul>
array(1) {
  ["check"]=>
  array(2) {
    [2]=>
    string(1) "1"
    [4]=>
    string(1) "1"
  }
}

なんか好きだ。

ちなみにvalue属性が無かったときは

<ul>
<li><input type="checkbox" name="check[1]" />1</li>
<li><input type="checkbox" name="check[2]" />2</li>
<li><input type="checkbox" name="check[3]" />3</li>
<li><input type="checkbox" name="check[4]" />4</li>
<li><input type="checkbox" name="check[5]" />5</li>
</ul>
array(1) {
  ["check"]=>
  array(2) {
    [2]=>
    string(2) "on"
    [4]=>
    string(2) "on"
  }
}

『on』という文字列が入る。(IE6~8,FF)

■参考

17.2 Controls

Modernizrにjsを追記して簡単にHTML5やCSS3の対応を確認する

以下を先頭に書く。

javascript:

Modernizrのソースを次にペーストしたら以下のソースを書く。

(function(obj){
	var txt = '';
	for(var i in obj){
		txt += i + ' : ' + obj[i] + '\n';
	}
	alert(txt);
})(window.Modernizr);

そうするとHTML5への対応やCSS3への対応がアラートされる。

Modernizr

頻繁に対応状況が変わるわけでないので無駄な作業な気がした。(´_`。)

■参考

http://www.modernizr.com/