2011/07/31

ファイルをブラウザにドロップして読み込む

ブラウザにドラッグしたファイルを読み込むには、「ドラッグ&ドロップを検出する」と同じように、dropイベントを補足し、「ローカルファイルを読み込む」と同じようにFileReaderでドロップされたデータを読み込むようにします。


下の四角にエクスプローラ/ファインダー等からファイルをドラッグすると、ブラウザにファイルを読み込みます。

ここにドロップして下さい。







<div id="dragAndDropSample" style="border: 1px solid #0000FF;border-radius:4px; width:300px; height:200px;" onDragOver="onDragOver2(event)" onDrop="onDrop2(event)">
ここにドロップして下さい。
</div>
<div id="info"></div>
<div id="view"></div>
<script type="text/javascript">
var info = document.getElementById("info");
var v = document.getElementById("view");
var fr = new FileReader();
function onDragOver2(event) {
    event.preventDefault();
}
function onDrop2(event) {
    var fs = event.dataTransfer.files;
    for ( var i = 0 ; i < fs.length ; i++) {
        var f = fs[i];
        info.innerHTML = "name:" + f.name + "  type:" + f.type + "  size:" + f.size / 1000 + " KB";
        if(/^image/.test(f.type)) {
            var img = document.createElement("img");
            fr.onload = function() {
                img.src = fr.result;
                v.appendChild(img);
            }
            fr.readAsDataURL(f);
        }
        if (/^text/.test(f.type)) {
            fr.onload = function() {
                v.innerHTML = fr.result;
            }
            fr.readAsText(f, "utf-8");
        }
    }
    event.preventDefault();
}
</script>

ローカルファイルを読み込む

ファイルを読み込むには、File APIのFileReaderを使用します。




0%





<input type="file" name="files[]" id="file" multiple onchange="readFile()">
<div id="progress">0%</div>
<div id="view"></div>
<script type="text/javascript">
function readFile() {
    var fs = document.getElementById("file").files;
    var v = document.getElementById("view");
    v.innerHTML = "";
    for ( var i = 0 ; i < fs.length ; i++ ) {
        var f = fs[i];
        var fr = new FileReader();
        var p = document.getElementById("progress");
        if (f.type == "image/jpeg" || f.type == "image/gif" || f.type == "image/png") {
            var img = document.createElement("img");
            fr.onload = function(event) {
                img.src = fr.result;
                v.appendChild(img);
            }
            fr.onerror = function() {
                v.innerHTML = "エラーが発生しました。";
            }
            fr.onprogress = function(event) {
                p.innerHTML = Math.floor(event.loaded / event.total) * 100 + "%";
            }
            fr.readAsDataURL(f);
        } else {
            fr.onload = function(event) {
                v.innerHTML = fr.result;
            }
            fr.onerror = function() {
                v.innerHTML = "エラーが発生しました。";
            }
            fr.onprogress = function(event) {
                p.innerHTML = Math.floor(event.loaded / event.total) * 100 + "%";
            }
            fr.readAsText(f, "utf-8");
        }
    }
}
</script>



上の例は、input要素でファイルを選択させ、選択後にファイルを読み込んでImageファイルの場合はimg要素を追加し、Image以外の場合はテキストとして読み込んで表示するようにしています。また読み込みの際、progressイベントを補足して進行度をパーセント表示させています。
FileReaderのメソッドは以下の物があります。


メソッド・プロパティ内容
readAsBinaryString(ファイル)バイナリとして読み込みます。
readAsText(ファイル, エンコーディング)テキストファイルを指定エンコーディングで読み込みます。
readAsDataURL(ファイル)ファイルをDataURL形式で読み込みます。
abort()ファイル読み込みを中断します。
resultメソッドの実行結果を参照します。


イベント一覧は以下の物があります。
イベント内容
loadstart読み込みが開始された
load読み込みが正常終了
loadend読み込みが終了(成功 or 失敗)
abort読み込みが中断された
error読み込みエラーが発生
progress読み込み中

ファイル情報を取得する

File APIを使用すれば、filesでファイル情報を取得してローカルにあるファイルにアクセスすることができます。
filesで取得できる情報には以下の物があります。


プロパティ内容
nameファイル名
typeファイルのMIME/TYPE
sizeファイルのバイトサイズ
urnファイルのURN










<input type="file" name="files[]" id="file" multiple onchange="getFiles()"><br>
<span id="disp"></span>
<script type="text/javascript">
function getFiles() {
    var files = document.getElementById("file").files;
    var disp = document.getElementById("disp");
    disp.innerHTML = "";
    for(var i=0 ; i < files.length; i++) {
        var file = files[i];
        disp.innerHTML += file.name + " : " + file.size/1000 + " KB type:" + file.type + " URN:" + file.urn + "<br>";
    }
}
</script>

ドラッグ&ドロップを検出する

ドラッグ&ドロップを検出するには、onDragStartのイベントを補足して、dataTransferのメソッドでデータを受け渡します。 draggable属性がデフォルトで有効なのはimg要素とa要素だけなので、その他はドラッグ&ドロップを行わせる場合は明示的にdraggable=”true”に指定する必要があります。

5つの花を四角の中にドロップして移動させるサンプルです。


ここにドロップして下さい。





<img draggable="true" id="flower" ondragstart="onDragStart1(event)" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrN7GoVUmc8GWwlCrypw4f2ZMFCMZCQJvAKGxFIa9wOqK_ECXHs-Zo2sI5otcUc07B6PTudt60HymlNn6UJeHVh9M1wyagAzFO3fjpphPCDWsapTAxssPY5rBUuYHNwIV2fVcAlmcCTAQR/s1600/_Sunflower.gif" />
<img draggable="true" id="dandellion" ondragstart="onDragStart1(event)" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUFRjLRFcgpbOK4Wsu1Vxn1JpTFdsudqjftA7aLis-DL6kfxPC1yVoZRtAos4VoZ4DP58387QcGMox9i6gCdFPzKH8XtVCBVszxWRlxALs8vSjzyVARrBhr5HduOB-9oVVl03CYs9x2dX9/s1600/Dandelion.gif" />
<img draggable="true" id="African Daisy" ondragstart="onDragStart1(event)" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-8DlPX2EtuZTqgNwmhVVe790bdl6-SjcPKssqbovYxDjigJnvbGl2H5w9M_cR27vCHUQZvWJpSlw_c4bkXhwBospATjzSqyfVtKZHleRSaAUp3DCs_sZl-z2fIlt1N6dWlJz-cXJqkWEd/s1600/African+Daisy.gif" />
<img draggable="true" id="Ixia" ondragstart="onDragStart1(event)" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1oL5S3SeWlU3KXi5FAVaKNkZmUbwPQwKxJhnLKxXkXev-IrCLET55LGMH9SZhxHxFktkwXmmdiBrSXE18-iETdWJ13MuOGplhjxGG7kBA7tu7H-zDKt9Hx2uWLT2gVTYna5a_dMp_LEYE/s1600/Ixia.gif" />
<img draggable="true" id="Spiked" ondragstart="onDragStart1(event)" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg15pYaJtscUa0JI3AnlUte5n4Ado14vWIyegi5RVaqYlvhw1DAfTgaBte3nLJIAT0udeKO6hkrEfktIP6Hv4jAUk8dKjaF6Srf-742mTLfGlzNIMnlo_veE8pJcPQ86PPpDdR0nqjeaET7/s1600/Spiked.gif" />
<br />
<div id="drop1" ondragenter="onDragEnter1(event)" ondragleave="onDragLeave1(event)" ondragover="onDragOver1(event)" ondrop="onDrop1(event)" style="border-radius: 4px; border: 1px solid #0000FF; height: 100px; width: 400px;">
ここにドロップして下さい。
</div>
<div id="debug">
</div>
<script type="text/javascript">
var debug = document.getElementById("debug");
function onDragStart1(event) {
 debug.innerHTML = "Drag Start";
 event.dataTransfer.setData("text", event.target.id);
}
function onDrop1(event) {
 debug.innerHTML = "On Drop";
 var id = event.dataTransfer.getData("text");
 var elm = document.getElementById(id);
 event.currentTarget.appendChild(elm);
 event.preventDefault();
}
function onDragOver1(event) {
 debug.innerHTML = "On Drag Over";
 event.preventDefault();
}
function onDragEnter1(event) {
 debug.innerHTML = "On Drag Enter";
}
function onDragLeave1(event) {
 debug.innerHTML = "On Drag Leave";
}
</script>



onDrop1 / onDragOver1にある、「preventDefault()」は、デフォルトではDropイベントが無効化されているので、このメソッド呼び出しでDropイベントを有効化しています。

メソッド・プロパティ内容
setData(key , value)ドラッグ&ドロップされるデータをセットする
keyには"text"か"url"のみ指定できる。
getData(key)ドラッグ&ドロップされたデータを取得する
keyには"text"か"url"のみ指定できる。
clearDataドラッグ&ドロップされたデータをクリアする
typessetDataメソッドでセットされた情報のtype(text/plain等)を取得する
files他アプリケーションからドラッグされたファイル情報を取得する
setDragImage(image, X, Y)ドラッグ中に表示されるイメージを指定する
addElement(element)ドラッグ中に表示されるイメージに要素を追加する

2011/07/30

SVGを描画する

SVGとは、Scalable Vector Graphicsの略です。
HTML5では、外部ファイルにある拡張子がSVGのファイルを読み込んで表示させることができます。
SVGファイルはその名の通りベクターベースなので拡大してもピクセルがカクカクになったりしないという利点があります。また、XMLベースなのでグラフィックツールなどを利用して簡単にデータが作成できるという利点もあります。

以下は四角形を描画する例です。





<svg height="150" width="300" xmlns="http://www.w3.org/2000/svg">
 <rect height="100" style="fill: orange;" width="100" x="30" y="30"></rect>
 <rect height="100" ry="8" style="fill: black;" width="100" x="150" y="30"></rect>
</svg>



円の例です。





<svg height="100" width="100" xmlns="http://www.w3.org/2000/svg">
    <circle cx="50" cy="50" r="50" style="fill: blue;" width="100" />
</svg>



楕円形です。





<svg height="100" width="100" xmlns="http://www.w3.org/2000/svg">
 <ellipse cx="50" cy="50" rx="50" ry="20" style="fill: skyblue;">
</ellipse></svg>




線の例です。





<svg height="200" width="200" xmlns="http://www.w3.org/2000/svg">
 <polyline fill="none" points="20,20 100,100 180,30" stroke-width="3" stroke="black"></polyline>
</svg>



ポリゴンの例です。





<svg height="200" width="200" xmlns="http://www.w3.org/2000/svg">
 <polygon fill="blue" points="20,20 100,100 180,30" stroke-width="3" stroke="black"></polygon>
</svg>



グラフィックツールを使えば、パスやグラデーションを使った以下の様な絵もSVGで描画可能です。





<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="レイヤー_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
     y="0px" width="300px" height="300px" viewBox="0 0 300 300" enable-background="new 0 0 300 300" xml:space="preserve">
<polygon fill="#FFFF00" stroke="#000000" stroke-miterlimit="10" points="153,184 100.271,158.186 49.113,186.988 57.37,128.863
    14.168,89.109 72,79 96.458,25.628 123.943,77.506 182.261,84.274 141.416,126.445 "/>
<path fill="#C7B299" stroke="#000000" stroke-miterlimit="10" d="M239.192,113.619c4.675,4.697,4.657,12.296-0.04,16.971L119,231
    c-4.697,4.675-14.052,25.583-18.727,20.886l-8.465-8.505C87.133,238.684,109.303,228.675,114,224l99.757-118.926
    c4.696-4.675,12.295-4.657,16.97,0.04L239.192,113.619z"/>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="207.1367" y1="233.4961" x2="281.1367" y2="233.4961" gradientTransform="matrix(-0.9478 0.3187 -0.3187 -0.9478 540.8281 359.5)">
    <stop  offset="0" style="stop-color:#FFFFFF"/>
    <stop  offset="0.1832" style="stop-color:#FAFAFA"/>
    <stop  offset="0.3909" style="stop-color:#EDEDED"/>
    <stop  offset="0.6108" style="stop-color:#D6D6D6"/>
    <stop  offset="0.8375" style="stop-color:#B6B6B6"/>
    <stop  offset="1" style="stop-color:#9B9B9B"/>
</linearGradient>
<circle fill="url(#SVGID_1_)" stroke="#000000" stroke-miterlimit="10" cx="235" cy="216.001" r="37"/>
<path fill="none" stroke="#000000" stroke-miterlimit="10" d="M211.001,187.823C220.17,191.074,227,203.575,227,218.5
    c0,13.298-5.423,24.673-13.091,29.294"/>
<path fill="none" stroke="#000000" stroke-miterlimit="10" d="M263.954,239.872c-6.184-2.017-12.876-13.377-15.964-27.979
    c-2.752-13.01-1.847-24.828,1.807-30.323"/>
</svg>




文字を描く例です。

テキストです。 パスに沿ったテキストです。



<svg height="200" width="400" xmlns="http://www.w3.org/2000/svg">
 <text fill="skyblue" font-family="sans-serif" font-size="30" stroke-width="1" stroke="blue" x="30" y="30">
テキストです。
 </text>
 <defs>
  <path d="M30,100 C100,100 150,200 200,100 C250,200 300,150 400,150" id="textPath1"></path>
 </defs>
 <text fill="skyblue" font-family="sans-serif" font-size="30" stroke-width="1" stroke="blue" x="30" y="100">
  <textpath xlink:href="#textPath1">パスに沿ったテキストです。</textpath>
 </text>
</svg>



以下は、外部にあるsvgファイルを表示する例です。ファイルは存在しないので以下ではエラーメッセージが表示されます。






<object data="svgファイルのURL" type="image/svg+xml" width="400" height="300"></object>


2011/07/29

canvas上でアニメーションする

canvas上でアニメーションをさせるには、javascriptで繰り返し描画を行います。


マウスを乗せると描画します。






<canvas id="drawAnimationOnCanvas1Canvas" style="border: 1px solid;" onmouseover="drawAnimationOnCanvas1();" width="400" height="300">
</canvas>
<script language="javascript" type="text/javascript">
function drawAnimationOnCanvas1() {
    var c = document.getElementById("drawAnimationOnCanvas1Canvas");
    var context = c.getContext("2d");
    var width = c.width;
    var height = c.height;
    var cx = 150;
    var cy = 150;
    var r = 150;
    var d = 0;
    var fontSize = 1;
    var fontAdd = 0.02;
    setInterval(fire, 50);
    function fire() {
        context.clearRect(0, 0, c.width, c.height);
        context.fillStyle = "#FFFFFF";
        context.fillRect(0, 0, c.width, c.height);
        var x = Math.cos(d * 360) * r + cx;
        var y = Math.sin(d * 360) * r / 2 + cy;
        context.fillStyle = "#000000";
        context.font = fontSize + "em 'Georgia'";
        context.fillText("This is not a Flash", x, y);
        d += 0.07;
        fontSize += fontAdd;
        if (3 < fontSize) fontAdd = -0.02;
        if (fontSize <= 0.25) fontAdd = 0.02;
    }
}
</script>

canvasにグラフを描画する

グラフを描画するには、canvas要素に「四角形を描く」や「線を描く」等で紹介したメソッドを使って地道に書いていくか、ライブラリを使います。
ライブラリの説明はそれぞれのサイトをご覧下さい。
RGraph
html5.jp


マウスを乗せるとグラフを描画します。






<canvas id="drawGraphCanvas1" onmouseover="drawGraph1();" style="border: 1px solid;" width="400" height="300">
</canvas>
<script language="Javascript" type="text/javascript">
function drawGraph1() {
    var c = document.getElementById("drawGraphCanvas1");
    var context = c.getContext("2d");
   
    // プロットデータ
    var month = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
    var attendance = [3, 5, 4, 7, 9, 5, 11, 13, 15, 20, 19, 22];
    var attendanceMax = 22;    // attendanceの最大値
   
    var originalPoint = 50;    // 原点座標
    var barInterval = 20;        // 棒グラフの間隔

    var graphHeight = c.height - originalPoint;    // グラフの高さ取得
    var graphWidth = c.width - originalPoint;        // グラフの幅取得
    // 1メモリの高さ
    var memHeight = Math.floor(graphHeight / attendanceMax);
    // 棒グラフの幅
    var barWidth = (graphWidth - barInterval * month.length) / month.length;
   
    // X軸を描画
    context.moveTo(originalPoint, graphHeight);
    context.lineTo(graphWidth + originalPoint, graphHeight);
    context.strokeStyle = "#121212";
    context.stroke();
    // Y軸を描画
    context.moveTo(originalPoint, 0);
    context.lineTo(originalPoint, graphHeight);
    context.stroke();

    // 棒グラフを描画
    var x = originalPoint + barInterval;
    var i = 0;
    for( i = 0 ; i < month.length ; i++) {
        context.fillStyle = "#FF1212";
        context.fillRect(x, graphHeight - (memHeight * attendance[i])
            , barWidth, memHeight * attendance[i]);
       
        context.fillStyle = "#000000";
        context.fillText(attendance[i], x, graphHeight - (memHeight * attendance[i]) - 3);
       
        context.strokeStyle = "#FF0000";
        context.stroke();
        context.fillStyle = "#121212";
        context.fillText(month[i] + "月", x, graphHeight + 15);
        x += barInterval + barWidth;
    }

    // メモリを描画
    var y = graphHeight - memHeight;
    for( i = 0 ; 0 < y ; i++) {
        context.strokeStyle = "#696969";
        context.moveTo(originalPoint, y);
        context.lineTo(graphWidth + originalPoint, y);
        context.stroke();
       
        if ( (i + 1) % 5 == 0 ) {
            context.fillStyle = "#000000";
            context.fillText(i + 1, originalPoint - 20, y);
        }
        y -= memHeight;
    }
}
</script>