インスタンス名.getMesh()[41].x += 40; // ------------- 頂点座標の移動
インスタンス名.draw(); // ------------- 再描画実行

インスタンス名.stroke(false);
インスタンス名.getMesh()[41].x += 40; // ------------- 頂点座標の移動
インスタンス名.draw(); // ------------- 再描画実行

インスタンス名.stroke(false);
スライドはこちらです。
赤い点をドラッグしてみてください。
あくまで基礎中の基礎なので、もっと詳しい方はこちらのほうがおすすめです。
「2009-02-11 - 最速チュパカブラ研究会」
http://d.hatena.ne.jp/gyuque/20090211#1234364019
例えば正面を向いている画像が上を向いているように見せるにはどうすればよいでしょう?
それは、画像を台形にして上辺が狭くなれば、立体的に上を向いているように見えますよね?
今回はcanvas要素を使ってこういった画像を変形させることにします。
しかし、現在仕様が固まりつつあるcanvasの2Dレンダリング方式では、こういった画像に奥行を与える直接的な機能を持っていません。
つまり長方形のカタチから台形に変形させるのは簡単にできないというべきです。
Flash Playerはvar10からムービークリップ等を3D的に回転させたりすることが可能になりましたが、canvasの場合は何らかの方法で実現しないといけません。
(canvas、ではなく、正式には「CanvasRenderingContext2Dというcanvas内のオブジェクト」なんですが、便宜上canvasと言うことにします。)
画像が3D的に見えるように台形に変形させる前に、canvasでできる変形とはどういうものか、おさらいしておきましょう。
ここでいう「変形」というのは、以下のとおりで、これらは全てcanvasに直接備わっているので簡単に変形が可能です。
しかし、先ほども言いましたとおり、台形みたいに、あるいはもっと不規則な四角形に変形する命令(メソッド、といいます)は直接canvasには備わっていません。
例えば以下のような台形や不規則な形状の変形は簡単にはいきません。

よって、直接できないこれらの変形は次の方法を使うことで実現できます。
1枚の長方形を台形に変形させるには、左上と右下で三角形を作って2つに割ってしまいます。
三角形はマスク領域となり、左上と右下のそれぞれの三角形にクリッピングマスクするように画像を処理していきます。
なぜこういうことをするかというと、2つの三角形にそれぞれ別の変形を与えると、おおよそどんなカタチの四角形でも作ることが可能になります。
下図では、それぞれの三角形に対し、拡大または縮小、傾斜、移動といった、canvasで簡単にできるメソッドを使って別々の変形を与えてます。


まずは呼び方、座標のルールから決めましょう。
左上の三角形を「セグメント1」、右下の三角形を「セグメント2」と呼ぶことにします。
セグメント1、セグメント2の頂点は当然それぞれ3箇所あります。(三角形ですから)
この中で2つのセグメントは2つの頂点を共有しないといけません。
どこでしょう?
右上と左下ですね、これがくっついているべきですよね?
便宜上、ポイント0を左上、ポイント1を右上、ポイント2を左下、ポイント3を右下、
と、呼ぶことにしましょう。
ここまでが呼び方と座標のルールです。
そして今回使う画像のサイズは横400px、縦300pxとしましょう。
先ほど、canvasで簡単にできる変形として、拡大または縮小、傾斜、移動などがあると言いましたが、実はこれらを一回で行うメソッド、今回はsetTransformというメソッドを使います。
こちらにて解説されています。
http://www.html5.jp/canvas/ref/method/transform.html
計算方法は基本的な算数なので、苦手な僕でも何とか理解できました。
では実際画像を描画してみましょう。
セグメント1の「変形の基準点」、つまりどこを中心に変形していくかを決定するのはとても重要です。
これができないと、カタチ自体は変形できても、三角形の外にはみ出したりします。
セグメント1の「変形の基準点」はポイント0の位置にします。
その指定のやり方は、setTransformの第5,6番目の引数に、ポイント0のXとY座標を指定します。
例えば、画像のポイント0(左上)の位置がcanvasの左上からXが80px, Yが40pxだとしたら、
画像のdrawImage(img, 0, 0)にしておいて、setTransform(1, 0, 0, 1, 80, 40)とします。
ここ、大事です。
間違ってdrawImage(img, 80, 40)にすると、変形の基準点がポイント0基準になりません。
drawImageする座標は、canvasの左上の座標にしましょう。
setTransformによって 80px, 40pxの位置にちゃんと移動してくれます。

setTransform(1.3, 0, 0, 1, 80, 40)
とすることで、画像の横の長さがポイント0から移動後のポイント1まで拡大されます。
この計算方法を使って、画像の縦の拡大および縮小率も応用することができます、値はsetTransformの第4引数にいれます。

セグメント1はあと傾斜させて完成です。
ポイント1(右上)が下に40px動いたとします。
この時点で画像は右下下がりに傾斜しないといけません。
縦方向の傾斜の計算方法はこれだけです。
40(移動距離) ÷ 400(画像の横幅) = 0.1
この結果をsetTransformの第2引数にいれます。
この流れで横方向の傾斜も行ってみましょう、縦方向の傾斜と考えは同じです。
例えばポイント2(左下)が左に60px動いたとしましょう。
横方向の傾斜の計算方法は、移動距離が左(負の方向)なのでマイナスとなり、
-60(移動距離) ÷ 300(画像の縦の長さ) = -0.2
これをsetTransformの第3引数にいれます。
これで変形完了です。
三角形にするので、Illustratorでおなじみ「クリッピングマスク」と同じような機能をもつ、clip()というメソッドがあるので、それを使います。
canvasでパスによる図形を描くことができますので、moveToやlineToなどのメソッドで三角形を描いたあと、clipを実行してsetTransformで変形させて最後にdrawImageすると、画像は三角形の形で切り取られた格好になります。
原則、clipメソッドを使うときは、処理の前後にsaveメソッドとrestoreメソッドを使います。
例えばrestoreしないと、clip領域(マスク領域)が解除されません、状態をsaveメソッド実行時に戻すという繰り返しを行いましょう。
ここまでの結果にするには、以下のようなコードになります。
ctx.save(); //描画状態を記憶しておく(※1)
ctx.beginPath(); //パスを描画開始
ctx.moveTo(80,40); //ポイント0の座標
ctx.lineTo(600, 80); //ポイント1の座標
ctx.lineTo(20, 340); //ポイント2の座標
ctx.closePath(); //パスを閉じる、三角形の形が決まる
ctx.clip(); //上記のパス領域をクリッピング領域とする
ctx.setTransform(1.3,0.1,-0.2,1,80,40); //変形を実行
ctx.drawImage(img,0,0); //画像(写真)を描画、すでに変形されている
ctx.restore(); //クリップ領域を解除(※1)
ctx.strokeStyle = "red"; //線の色を赤にする(最終的に不要)
ctx.stroke(); //三角形の「線」を描く(最終的に不要)(※2)
(※1)
サンプルではこのコードが繰り返し実行されるため、クリップ領域も毎回解除しなければなりません。
saveによって、クリップ領域が存在しない状態を記憶しておき、restoreでsave時の状態に戻す作業をします。
この考え方はclipしながらアニメーションを行う際は必須のテクニックです。
(※2)
clipはstrokeして図形の線や塗りを描かないといけないと思われがちですが、closePathした時点でクリップ領域が決まるので、stroke(線)やfill(塗り)をする必要はありません。
↓↓このボタンを押して、クリップ状態と非クリップ状態を見比べてください。
セグメント2も基本はセグメント1と一緒です、応用は利きます。
ただ、大きく注意するべき点が1点、それは「変形の基準点」をどこにするか?です。
先ほどのセグメント1は分かりやすく、左上が基準点になれば良かったんですが、
『セグメント2にとってポイント0(左上)の座標は全く意味がない』
ということです。
セグメント2の持つ座標はポイント1から3までです。
ポイント0がどこに行こうが、セグメント2の三角形は影響を受けない(変形しない)というわけです。
要するにセグメント2になったら変形の基準点を別のどこかに指定し直さないといけないということです。
一番分かりやすかったのが、ポイント2(左下)の位置を基準として、そこから伸縮や傾斜を行おうと思います。
よってsetTransformの5,6引数目には、ポイント2のXとY座標をいれるのですが、ここでdrawImage(img, 0, 0)にすると、ポイント2から画像が描画されるので、ポイント2の下に画像が配置されます。
なので、drawImageの第3引数のY座標を画像の高さ分上に配置します。
つまり、今回の画像の高さが300pxなので、drawImage(img, 0, -300)とすることで、画像の左下が基準点にぴったり合った状態になります。

これまでが、セグメント1との基準点を考える上での違いです。
↓↓このボタンを押して、クリップ状態と非クリップ状態を見比べてください。
さて、いよいよ結果を見ることができます。
セグメント1とセグメント2にそれぞれ別の変形を与えて表示させてみましょう。

これを見てどうでしょう?
満足しました?
僕はとても不満というか残念です、なんでしょう?この継ぎ目。
各ブラウザともどうやらこのような仕様になっているようで、クリップの痕が残ってしまい、継ぎ目に隙間が出ます。
三角形を継ぎ合わすだけでは解決できません。
ここは一つ、簡単な方法で解決してみましょう。
アイデアとしては、セグメント1のクリップ領域を、三角形ではなく、四角形にしようという単純なものです。
つまり、セグメント1の『左上→右上→左下』だった三角形を、『左上→右上→右下→左下』にして、四角形にしてしまい、上にセグメント2を「乗せる」ように見せて隙間をなくすという方法。
ただし、セグメント1は無駄な領域までレンダリングしてしまうので、パフォーマンス的に良いかどうかは、実用レベルだと別な方法も検討しないといけないかもしれません。

こういったことをやってくれるライブラリはあるんですが、HTMLをベースとしたPCやスマートフォンの描画系アプリケーションの開発のためには、原理くらいはある程度おさえておいた方がいいかな?と思ってたんですが、結構難しいですね。
何でもライブラリに頼ろうとすると、案件仕様によっては実現困難になりそうなので、画像を変形させる基本中の基本だけでも学んでおきたかったわけです。
もちろん、このままでは何にもなりません。
今回は一つの画像を2個の三角形で分割しましたが、例えば、画像を布やゴムのようにグニャグニャにしたり、扇形にしたり、3D形状にしたり、となると、今回の写真をもっと多く分割していかないといけません。
すると、今回の方法から違う計算方法などを使って実装しないといけなくなるかもしれません。
とにかくまだまだ勉強することはあるってことで。
以上、夏休みの自由研究でした。
以前ブログにも書きましたjQuery用のプラグイン、jquery.monochromer.jsですが、ある件でこのプラグインを紹介してくださるらしく、ちょっと改良しました。

色を指定できるデモとソースのダウンロードはこちらでお願いします。
どういったものかというと、img要素にこれを適用すると画像がモノクロになるというものです。
適用方法は簡単で、jQueryを読み込んだ後このプラグインを設置し、指定するだけです。
一番シンプルなカタチ。
monochromerをデフォルトの状態で与えてください。
img要素がグレースケール化します。
本の画像にマウスを乗せるとカラーになります。
今回はイヤラシく、僕も執筆に参加した宣伝も兼ねて「Facebookページ プロフェッショナルガイド」のサムネイルを使います、ゴメンナサイ。
$(".demo01 img").monochromer();
改良点ですが、HTML5のcanvasを使っています。
IE8までは、「なにもしないプラグイン」というように、内部でブラウザ判定をしてます。
つまりIE6などでは、画像が表示されるだけなので、必要最低限の表示は出来ます。
新しいブラウザは機能が増え、古いブラウザはそのままで、、という感じでしょうか?
今度はカラーを指定します。
monochromerのcolorパラメータに、16進数のCSSカラー値を指定します。
この例は#f00、もちろん#ff0000でもOKです。
$(".demo02 img").monochromer({color: "#f00"});
しかし、いきなりページが表示されて画像がモノクロになるとおかしいですね。
通常はカラーのまま、マウスオーバーでモノクロ、という流れにしたいときには、typeパラメータを"false"にしたらOKです。
$(".demo03 img").monochromer({color: "#f00", type: false});


今度は二つ並べました。
こういったレイアウトをするときは、imgに親要素で囲ってください。
今回はli要素で囲み、liをfloat: leftしてます。
monochromerの指定はcolorパラメータに"sepia"と"blue"を指定しました。
$(".demo04 li:first-child img").monochromer({color: "sepia", type: false});
$(".demo04 li:nth-of-type(2) img").monochromer({color: "blue", type: false});


ここでaタグを付けないと指マークにならないのですが、Webアプリケーションを制作していると、どうしてもa要素ナシでマウスを指マークにしたいことがあったとしましょう。
この時、実はプラグインの内部的な都合で、CSSでimgに「cursor: pointer;」としても指マークにならないので、パラメータをひとつ追加しました。
それがCSSのcursorプロパティの名前、そのもので、以下のように追記します。
これでマウスを乗せてください、マウスの形が変わると思います。
$(".demo05 li:first-child img").monochromer({color: "sepia", type: false, cursor: "pointer"});
$(".demo05 li:nth-of-type(2) img").monochromer({color: "blue", type: false, cursor: "crosshair"});

内部的にcanvas要素を生成して、img要素のピクセルをcanvasに取り込み、変色させています。
img要素とcanvas要素はCSSのpositionで重ねて、その親にspan.monochrome-wrapという要素を生成しています。
レイアウトをするとき、img要素にmarginとpaddingとborderとfloatを指定すると、span.monochrome-wrapに適用します。
しかし他のCSS設定は無視されますので、例えばtransformとかで、マウスオーバーでscaleによって大きくしたり、とかが出来ません。
なので、内部的に生成されたspan.monochrome-wrapに対してCSSを当てるといいです、以下のようなCSS設定でマウスを載せると大きく見せられます。
.demo06 span.monochrome-wrap {
-webkit-transition: .3s;
}
.demo06 span.monochrome-wrap:hover {
-webkit-transform: scale(1.2);
}
将来的には、img要素に指定したCSSプロパティを全部span.monochrome-wrapに適用させたいところ。
実は試したのですが、クロスブラウザの作業でどうしてもうまくいきませんでした。
ぜひ改良したいなあ、と思います。
あと大事なことなんですが、canvasの仕様でドメインの違う画像のピクセルを操作することは出来ないことに鳴っているようです。なので、同じドメイン内の画像だけにおいて使うとよいでしょう。
var img = $(this); // <img>を指すimg.src = 画像のパス + "?" + new Date().getTime();img.onload = function () { //読み込み完了後の処理
<img src="image01.jpg" alt>
//jQuery使用ですvar img = $(this); // <img>を指すvar ua = $.browser;if(ua.msie && img.width() !=0) { imageLoaded();}else{ img.load(imageLoaded);} function imageLoaded (){ //読み込み完了後の処理








