Canvasフレームワークの作成:オブジェクトとマウス





Canvasについて質問ので、最もよく寄せられる質問は、フレームワークの内部-フレームワークに実装されているマウスが要素の上にあることを理解する方法についてでした。 このトピックでは、 AtomJSに基づいた同様のCanvasフレームワークを実装しています。





グローバルインターフェース



まず、フレームワークのインターフェースを考えてみましょう。 略してCanvas Frameworkと呼びましょう-CF。 これは、インスタンス化のためのグローバルファクトリ変数になります。

最初の引数には、目的の要素へのリンクを渡します。



var cf = new CF('#my-canvas');
      
      







実装は簡単です。

 window.CF = atom.Class({ initialize: function (canvas) { this.canvas = atom.dom( canvas ).first; this.ctx = this.canvas.getContext('2d'); } });
      
      







次に、このエンティティを使用してオブジェクトを作成できます。



 cf.circle([50, 50, 10] , { fill: 'red' , hover : { fill: 'blue' } }); cf.rect ([10, 10, 20, 20], { fill: 'green', hover : { fill: 'blue' } });
      
      







簡単にするために、すべてのオブジェクトがプルオーバーされ、マウスイベントをリッスンします。



数値の実装



ここで、Figureの基本クラスを定義する必要があります。



 //    var Shape = atom.Class({ Implements: [ atom.Class.Events, atom.Class.Options ], cf : null, data : null, hover: false, path: atom.Class.abstractMethod, initialize: function (data, options) { this.data = data; this.setOptions( options ); }, hasPoint: function (x, y) { var ctx = this.cf.emptyCanvas.ctx; this.path( ctx ); return ctx.isPointInPath(x, y); }, draw: function () { var ctx = this.cf.ctx, o = this.options; this.path( ctx ); ctx.save(); ctx.fillStyle = this.hover ? o.hover.fill : o.fill; ctx.fill(); ctx.restore(); } });
      
      







emptyCanvasが必要になることがわかります。これは非表示のCanvasであり、「バトル」キャンバスのパスに違反しないようにパスを描画します。 CFコンストラクターを更新します。



 window.CF = atom.Class({ initialize: function (canvas) { [...] this.emptyCanvas = atom.dom.create( 'canvas', { width: 1, height: 1 }).first; this.emptyCanvas.ctx = this.emptyCanvas.getContext('2d'); } });
      
      







継承する各図は、パスメソッドを実装するだけで済みます。 いくつかの図形、長方形と円を追加しましょう。



 // circle.data == [x, y, radius] var Circle = atom.Class({ Extends: Shape, path: function (ctx) { ctx.beginPath(); ctx.arc( this.data[0], this.data[1], this.data[2], 0, Math.PI * 2, false ); ctx.closePath(); } }); var Rect = atom.Class({ Extends: Shape, path: function (ctx) { ctx.beginPath(); ctx.rect.apply( ctx, this.data ); ctx.closePath(); } });
      
      







次に行う必要があるのは、マウスの実装です。 Canvas要素のmousemoveイベントにサブスクライブし、カーソルの位置を記憶します。 マウスは、チェック、ホバーの変更、およびそれらのmousedownイベントとmouseupイベントを呼び出すShape要素を受け取ります。 クロスブラウザとの互換性に問題があることがわかります。OperaにはlayerX / Yコードはなく、offsetX / Yを使用する必要があります。 重要ではありませんが、最も重要なこととして、それについて知ってください)



 var Mouse = atom.Class({ x: 0, y: 0, initialize: function (canvas) { this.elements = []; canvas.bind({ mousemove: this.move.bind(this), mousedown: this.fire.bind(this, 'mousedown'), mouseup: this.fire.bind(this, 'mouseup' ) }); }, add: function (element) { this.elements.push( element ); }, move: function (e) { //   layer*,        if (e.layerX == null) { // opera this.x = e.offsetX; this.y = e.offsetY; } else { // fx, chrome this.x = e.layerX; this.y = e.layerY; } this.elements.forEach(function (el) { el[i].hover = el[i].hasPoint(this.x, this.y) }.bind(this)); }, fire: function (name, e) { this.elements.forEach(function (el) { if (el.hasPoint(this.x, this.y)) { el.fireEvent(name, e); } }.bind(this)); } }); //    : window.CF = atom.Class({ initialize: function (canvas) { [...] this.mouse = new Mouse( this.canvas ); } });
      
      







次に、キャンバスの更新が必要です。



 window.CF = atom.Class({ initialize: function (canvas) { [...] // 25 fps this.update.periodical( 1000/25, this ); }, update: function (shapes) { this.ctx.clearRect(0,0,this.canvas.width, this.canvas.height); this.elements.invoke('draw'); } });
      
      







グローバルオブジェクトを編集して、要素を作成できるようにします。

 window.CF = atom.Class({ [...], elements: [], _shape: function (Class, args) { var e = new Class(args[0], args[1]); this.mouse.add( e ); this.elements.push( e ); e.cf = this; return e; }, circle: function (data, options) { return this._shape(Circle, arguments); }, rect: function (data, options) { return this._shape(Rect, arguments); } })
      
      







すべて、アプリケーションを作成します。



 var write = function (msg) { atom.dom.create('p').text(msg).appendTo('body'); }; var cf = new CF('canvas'); cf.circle([50, 50, 10] , { fill: 'red' , hover : { fill: 'blue' } }) .addEvent('mousedown', write.bind( window, 'circle mousedown' )); cf.rect ([10, 10, 20, 20], { fill: 'green', hover : { fill: 'blue' } }) .addEvent('mousedown', write.bind( window, 'rect mousedown' ));
      
      







結果





おわりに



実際、フレームワークには、この記事で説明されている以上のものがあります。 たとえば、説明されている例は、絶対に配置されたキャンバス上でのみステアリングされ、最適化、ニュアンスなどの束もあります。 アプリケーションのfpsを調整し、変更のみでキャンバスを更新し、マウスの動きではなく、レンダリングの前にステータスを更新する必要があります。 これは大変で骨の折れる作業です。 ゼロから実装するよりも、準備が整ったものを使用する方が適切です。



ところで、 map + areaを使用する別の方法があります。 利点はありますが、欠点もあります。 これらは同期の難しさであり、最も重要なことは、 より複雑な図を実装できないことです。



SVGをテーマにしたトローリングの愛好家-お待ちください。 Canvasを使用する理由があります。 さらに、このトピックはトレーニングの質において悪くありません。 したがって、少なくとも今回はホリバーなしで行うようお願いします。 そして、あなたはすでに疲れています



All Articles