キャンバス技術の共有

キャンバスの紹介

新しいテクノロジーを学ぶ前に、このテクノロジーの歴史的な発展と原因を理解することは、このテクノロジーをより深く理解するのに役立ちます。

歴史的に、canvasはMac OS X Webkitでコントロールパネルコンポーネントを作成するためにApple Inc.によって最初に提案されました。canvasがHTMLドラフトおよび標準と呼ばれる前は、批判されるなど、いくつかの代替方法を使用して描画しました。 Flash、および非常に強力なSVG(スケーラブルベクターグラフィックス、スケーラブルベクターマークアップ)、およびIE(IE 5.0以降)でのみ使用できるVML(ベクターマークアップ言語、ベクターマークアップ)。一部のフロントエンドでも、div + cssを使用して描画を完了することができます。

一般に、キャンバスがない場合、ブラウザでのグラフィックスの描画はより複雑になり、キャンバスが表示された後は、2Dグラフィックスの描画は比較的簡単になります。

注:divを使用して、長方形、円、三角形、台形などの単純なグラフィックスを描画しますが、それほど複雑ではありません。

しかし、キャンバスにも欠点があります。それは自然とのキャンバスですので、関連解像度布のデジタル写真を、それが描画キャンバスの表示内容が異なることになる異なる解像度で運命にあります。また、コンテンツキャンバスの描画は、任意のDOM要素に属していない、要素ブラウザビューアは、どのコンテンツで、それは明らかである彼らは、これら2つの側面は、SVGキャンバスとして良いとしてではないことをキャンバス上でマウスクリックを検出できないことを見つけることができませんの。

例:CSSを使用してキャンバス要素のサイズを設定すると、描画されたグラフィックが歪む可能性があります(長方形から正方形、円形から楕円形など)。これは、キャンバスサイズと要素サイズが異なるためです。要素のサイズに自動的に適合します。2つの要素が比例している場合、キャンバスは歪みなく比例してスケーリングされます。

このように、canvasには明らかな欠点があります。SVGを直接使用する方が良いでしょうか?

いいえ、一言聞いたことがありますか?完璧な解決策はなく、適切なものだけです。

SVGはXMLに基づいているため、SVG内の要素はDOM要素と見なすことができ、DOM操作を有効にできます。同時に、SVGに描画された各画像はオブジェクトと見なされます。SVGオブジェクトのプロパティが変更された場合、ブラウザはグラフィックを自動的に再現します。

上記はSVGの利点ですが、この利点を通じて、いくつかの問題を見つけることもできます。

  1. 通常、DOMを過度に使用するアプリケーションは非常に遅くなるため、複雑なSVGを使用するとレンダリングが遅くなります。しかし、マップなどのアプリケーションでは、SVGが最初の選択肢です。
  2. ブラウザの再配置は、ブラウザウィンドウの変更、要素サイズの位置の変更、フォントの変更などが発生したときに行われます。
  3. DOM操作を有効にできる場合でも、DOM操作のコストは比較的高くなります(DOMとJSは別々に実装されます)。

トピックに戻ります。

2Dグラフィックス・キャンバスではJavaScriptを通って引き込まれると、<canvas>自身が任意の電力を消費していないラベルは、それだけでコンテナです。描画時には、キャンバスがピクセルごとにレンダリングされます。グラフィックが描画されると、要素はブラウザに関係しなくなります(スクリプトは終了し、描画されたグラフィックはDOMの一部ではありません)。

それは、(HTML標準で、ことは注目に値するWHATWG標準はで明示的に記述):著者で使用しないでくださいcanvas。際に利用できるA、より適切な要素文書Aの要素ので、要素を乱用しないでください。

キャンバスは現在、ほぼすべてのブラウザのサポートですが、IE 9.0以前のバージョンはサポートしていないcanvas要素を

キャンバスの基本的な使い方

CanvasはHTML要素なので、canvasを使用するには、最初に次のことを行う必要があります。

<canvas id="canvas" width="600" height="300">
    当前浏览器不支持canvas
</canvas>

HTMLコードの最初の行では、あなたが2つのプロパティを見ることができますwidthし、heightCSS所定のサイズを使用していない、言及した上で、キャンバスの幅と高さを示している、一貫性のない大きさとCSSの割合は、キャンバスサイズの所定のときので、比例して拡大縮小できないため、グラフィックが歪んでいます。キャンバスサイズが設定されていない場合、キャンバスはデフォルトで300px * 150pxキャンバスに初期化されます。

「現在のブラウザはキャンバスをサポートしていません」は要素のコンテンツですが、フォールバックコンテンツ(つまり、フォールバックコンテンツとしてのみ使用されます。このコンテンツは、ブラウザがキャンバスをサポートしていない場合にのみ表示されます。

canvas要素自体には描画機能はありませんが、コンテナーとしてのみ機能するため、JavaScriptなどのスクリプトを通じて描画する必要があります。

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

キャンバスを使用するには、上記のHTML + JSコードが必要です。どのコンテンツを描画する場合でも、これらの数行のコードは不可欠です。

getContext()これは、描画コンテキスト(またはレンダリングコンテキスト)を取得するためにcanvas要素によって提供されるメソッドであり、パラメーターは1つだけです:コンテキストフォーマット。ここで渡すこと2dは、2D画像描画環境を取得することを意味します。getContextcanvas要素が提供するメソッドあるため、メソッドgetContextの存在を検出することでブラウザのサポートを確認できます。

コンテキスト変数のタイプはCanvasRenderingContext2Dです。

レンダリングのコンテキストを理解するのは簡単ではありません。描画のブラシとして理解できます。

キャンバス上の描画位置を決定する方法は?座標です。

キャンバスでは、キャンバスの左上隅が原点で、横軸は幅のx軸、縦軸は高さの[y]軸です[^ 1]。原点の位置は移動できますが、とりあえず原点の移動は考慮しません。

W3C学校、提供描画キャンバスAPIは大まかに分け、以下の[^ 2]:

  1. 色、スタイル、影
  2. 線のスタイル
  3. 長方形
  4. パス
  5. 変換
  6. テキスト
  7. 画像のレンダリング
  8. ピクセル操作
  9. 合成
  10. その他の

キャンバスの組み合わせ例

上記の例では、長方形、円、線、テキスト、「テキスト」が含まれていますが、詳細には、この記事が非常に長くなるAPIが多数含まれるため、不要です。言及されているのは、2次元グラフィックアプリケーションの数学的な曲線であるベジェ曲線です。一般的なベクトルグラフィックソフトウェアは、それを使用して曲線を正確に描画します。ベジェ曲線は、コンピュータグラフィックスで非常に重要なパラメータ曲線です3]。

一次ベジェ曲線

二次ベジェ曲線

3次ベジエ曲線

上の画像は、1次ベジェ曲線、2次ベジェ曲線、3次ベジェ曲線です。この図から、1回限りのベジェ曲線は実際には直線であることがはっきりとわかります。もちろん、より高次の曲線がありますが、キャンバスは2次および3次のベジェ曲線しか提供しません。

例として、2次ベジェ曲線のAPIを取り上げます。

quadraticCurveTo(cp1x, cp1y, x, y);

(cp1x、cp1y)は制御点の座標を表し、(x、y)は終点の座標を表します。(x0、y0)であると仮定すると、まだ開始点座標がありません。これは(x0、y0)ですか?

呼び出しているquadraticCurveTo関数で、座標は(コンテキストを描画)するコンテキストを。たとえば、次のとおりです。

var cxt = canvas.getContext('2d'); // 认为canvas已经获取到
cxt.beginPath();
cxt.moveTo(120, 90);
cxt.quadraticCurveTo(130, 80, 130, 70);
cxt.quadraticCurveTo(115, 70, 115, 50);
cxt.quadraticCurveTo(115, 30, 155, 30);
cxt.quadraticCurveTo(195, 30, 195, 50);
cxt.quadraticCurveTo(195, 70, 155, 70);
cxt.quadraticCurveTo(135, 90, 120, 90);
cxt.stroke();

このコードを実行すると、ダイアログボックスが表示されます(最初の図を参照)。ご覧のとおり、2次ベジェ曲線を呼び出す前に、開始点を設定します。つまり、ブラシを座標(120、90 )、以降の呼び出しでは、前のベジェ曲線の終点がこの曲線の始点として使用されます。

現在、この質問をする人もいるかもしれmoveToません。この通話を削除すると、抽選できませんか?後続のlineTo関数が呼び出された場合、実際には描画できません。しかし、忘れないでください。別のベジェ曲線があります。これは直線です。彼は(cp1x、cp1y)を始点とし、(x、y)を終点とする直線です。したがって、moveToそれを削除すると、最初の曲線の描画にのみ影響します。ただし、コードの最後の行を削除するとstroke()、プログラムの終了時にブラウザに何も表示されなくなります。

このことから、別の質問について考えるstroke()必要があります。なぜ関数が必要なのでしょうか。

実際、canvasは状態ベースの描画であり、canvasが提供するAPIは、状態設定と特定の描画の2種類に分類できます。

stroke()fill()その他の機能は、コンテナキャンバスキャンバスの内容を描画するための機能です。

arc()lineTo()rect()およびその他の機能は、ブラシの状態の機能が提供されます。

その幻想型の映画やTVシリーズでは、道教の虚無のシンボルがよく見られますが、描いた後、前に押すと対応するシンボルや人物に印刷されます。

道教の空のシンボル、このプロセスはキャンバスのブラシの状態を設定するプロセスに似ています。

押し進めてください、これは特定の描画です。描画方法がわかりません。とにかく、このシンボルが描画されます。(前に述べたように、キャンバスは、ピクセルレンダリングによって画素の)

「テキスト」図面、このテキストは引用されている、通常のテキストであることに注意してください。図面を呼び出すだけfillText()でよく、ここでのテキストは、シングルチップやLCDなどのプログラムでドットマトリックスフォントを示します。一連のドットはテキストまたはパターンを表示します。ライティングプロセスはより複雑です。LCDのピクセルは、ピクセルが1に設定されている場合は点灯し、0の場合は点灯しないことを理解できます(実際は逆である場合があります)。その後、キャンバスでの「テキスト」描画は同じです。テキストに対応するフォントライブラリを確立して、特定のテキストを描画する必要がある場合は、フォントライブラリで対応するテキストドットマトリックスを見つけ、ドットマトリックスを1としてマークします。位置が点灯します(塗りつぶされます)。

実際の操作では、ライトアップするのはそれほど簡単ではないかもしれません。クールなコンテンツを作成したり、円で塗りつぶしたり、長方形で塗りつぶしたり、動的な爆発効果を作成したりすることもできます。他のいくつかの計算に。

長方形の塗りつぶし

上の画像は長方形で塗りつぶされた例で、数字は8x8ドットマトリックスに対応しています。

キャンバスの高度なアニメーション

まず、問題について考えてみましょう。ここで、円を描く方法を学習したとしましょう。次に、物理学に関連するアニメーションを作成する必要があります。

今それを達成する方法は?

この問題を目にしたとき、突然混乱する人もいます:私は円を描く機能を学び、そのような難しいアニメーションをシミュレーションさせてくれました。

高校の物理学で学んだフラットスローモーションは、基本的に小さなボールの問題にすぎないと考える人もいるでしょう。2次元平面では、この小さなボールは円と見なすことができますが、描くことを学ぶ必要があるだけです。ただの円?

この後も、横方向のスローモーションのボールが重力を除いて水平方向の初速度v0を持っていると仮定して、他の外力の影響を受けない、つまり重力加速度g(計算を簡単にするために、次のように、単純に)に設定できます。g = 10m/s^2垂直方向の初期速度vh(またはと呼ばれますvh = 0;はありません

フラットスロー

写真から、ボールの水平方向がキャンバスの水平軸とまったく同じであり、垂直方向も垂直軸と一致しているなど、いくつかの非常に興味深い現象を見ることができます。

次に、フラットスローモーションに対応する物理式:

// 竖直方向无初速度,水平方向没有外力
x = v0 * t; // 水平方向位移
h = 1/2 * g * t * t; // 竖直方向位移

// 竖直方向有初速度
h = vh * t - 1/2 * g * t * t; // 竖直方向位移

座標(x、h)とキャンバス(x、y)は同じであり、物理的な問題を実行していないことがわかります。つまり、パラメーターv0、t、g、vhは既知であり、必要なのは、いつでも(x、h)を計算することです。つまり、キャンバス上のボールの座標(x、y)です。

分析の最後に、いつでもボールの位置座標を取得できるようになりました。それから、いつでもキャンバスにボールを描くことができます。

上記の分析によると、一部の人々は言うかもしれません:あなたは間違っている、あなたは特別である必要がありますボールは必ずしも左から投げられるとは限らず、右から投げることもできます。

実際、上記の分析は、空間に限定された(そしてこの記事のトピックは物理学ではなくキャンバスである)研究対象のより特別な状態の1つを取り出しただけであり、より一般的な結論に一般化されませんでしたが、実際には、これらの分析は変位であるかどうかで十分ですまたは速度、彼は方向付きのベクトルであり、次に規定したいと思うかもしれません:キャンバスの座標軸を取り、値が増加する方向は正の方向です、そしてそれを右側から投げます、それはと表現できる逆方向と見なすことができ-v0、最後に計算を通じて変位の式は正しい座標を取得できます(ただし、今回は座標xを計算するのが面倒なので、上記の式を直接使用することはできません)。

私はこれまで多くのことを分析してきましたが、私たちは実現に最も関心があると述べました。

以前の分析では、ボールの位置座標をいつでも検索する場合、必要なパラメーターはv0、t、g、vhです。これらのパラメータはどこに保存する必要がありますか?このデータ構造を設計する方法は?

もちろん、これらのパラメーターをグローバル変数として直接設定することもできますが、これは明らかに適切ではありません。これらのパラメーターの中で、グローバル変数の適切な設定は重力加速度gのみです。また、v0、t、vhはボール自体の「プロパティ」である必要があるため、クラスに抽象化する必要があります。

function Ball(r, v0, vh, t) {
    this.r = r;
    this.v0 = v0;
    this.vh = vh;
    this.t = t;
    this.x = 0;
    this.h = 0;

    this.calcX = function() { /* 计算水平位移 */ }
    this.calcH = function() { /* 计算竖直位移 */ }
}

var ball = { x: 0, h: 0, r: 10, v0: 0, vh: 0, g: 10};
// 重力加速度无论是作为全局变量还是小球属性,均可

// es6之后
class Ball {
    constructor();
}

上記の3つの方法にはそれぞれ利点があり、適切な方法を選択するだけです。

「あなたは私が物理学の大きな頭を持っていると言います。もっと簡単なものはありますか?」

いずれにせよ、物理シーンを100%削減する必要はありません。

var ball = { x: 0, y: 0, r: 10, vx: 5, vy: 0, g: 5 };
setInterval(() => {
    ball.vy += ball.g; // 竖直方向速度增加
    ball.y += ball.vy; // 竖直方向位移
    ball.x += ball.vx; // 水平方向位移
    cxt.clearRect(0, 0, 800, 300);
    cxt.beginPath();
    cxt.fillStyle = 'black';
    cxt.arc(ball.x, ball.y, ball.r, 0, 2*Math.PI);
    cxt.fill();
}, 50);

了解しました。

これはもう少し高度なアニメーションです。いくつかの機能を学習している可能性があり、このアニメーションはより見事になります。たとえば、長方形の塗りつぶしを学び、rgbaの知識を少し習得したら、「尾」、つまりロングテール効果を作成できます。具体的には、上記のコードcxt.clearRect()を次のコードに置き換えます

cxt.fillStyle = 'rgba(255, 255, 255, 0.2)';
cxt.fillRect(0, 0, 800, 300);

これにより、コーディングが非常に強力であるように見えます。

この手順を実行してもまだ満足できるものではありません。ボールが勢いよく落下し、しばらくするとアニメーションが消えます。

問題はありません衝突検出」を実行できます背の高い語彙のように見えますが、実際には背が高くありません。このセクションの最初の部分の分析に基づいた場合、衝突によって引き起こされる運動量の損失を考慮する必要がありますが、これは非常に複雑です。

しかし、簡略化されたバージョンは簡単に言うことができます。ボールが上下の境界に当たり、上下方向の速度が逆転し、速度が半分になります。左と右の境界線も同様に扱うことができます。

if (ball.r + ball.x > canvas_width) {
    ball.vx *= -0.5
}
if (ball.r + ball.y > canvas_height) {
    ball.vy *= -0.5;
}

注:衝突検出とは、ここでは「境界検出」を指します。ボールが境界に落ちたときに落下を続けても意味がないのは、背後のアニメーションが見えないためです。つまり、境界に達したときに停止するか、再起動するか、その他の処理を行うかのいずれかです。つまり、意味のないアニメーションは表示されません。

以前にプレイした貪欲なヘビと同様に、さまざまな壁があります。制御されたヘビが壁に触れると、ゲームは失敗します。壁がない場合、ヘビは反対方向から出てきます。

まとめ

この記事では、さまざまなデモを直接リストして関数を紹介するだけでなく、キャンバスにAPIをあまり多く導入しないようにしています。

個人的には、canvasは実際には関数ライブラリです。通常、Each、splice、split、map、reduceに使用するものと同じです。これらはパッケージ化されており、直接使用されます。使用方法については、関数のマニュアルを確認してください、それを数回よく知っています。

私が大学に初めて入学したとき、専門の先生がプログラム=アルゴリズム+データ構造と言っていましたが、今でも多くの人がこの点を強調しています。ハートがある場合は、前のセクションを思い出してください。フラットトスの動きを分析するときは、基本的にアルゴリズムを検討します。ボールクラスを設計するときは、オブジェクト指向を検討しますが、データを検討する場合はさらに多くなります。構造問題は、これらの内容を検討した後、具体的に実現し始めました。

参考資料:

[^ 1]:MDNドキュメント
[^ 2]:HTML 5 Canvasリファレンスマニュアル


この記事は最初に個人のブログで公開されました。^-^へようこそ。
スイープして毎日少しずつ上達していきます〜

おすすめ

転載: blog.51cto.com/12419668/2486697