ホームページ > 記事 > ウェブフロントエンド > Canvas ゲーム開発学習パート 6: スタイルと色の使用 (2)
線のスタイル
一連のプロパティを通じて線のスタイルを設定できます。
lineWidth = value lineCap = type lineJoin = type miterLimit = value
これらのプロパティについて詳しく説明しますが、次の例を使用すると理解しやすいかもしれません。
lineWidth属性の例
この属性は、現在描画されている線の太さを設定します。プロパティ値は正の値である必要があります。デフォルト値は 1.0 です。線の幅は、中心から側面までの特定のパスの太さを指します。つまり、パスの両側に線幅の半分を描きます。キャンバス座標はピクセルに直接対応していないため、正確な水平線または垂直線を取得する場合は特別な注意を払う必要があります。以下の例では、幅を増やしながら 10 本の線が描画されます。一番左の線の幅は 1.0 単位です。 さらに、パスの位置決めの問題により、最も左の線と奇数の幅を持つすべての線を正確にレンダリングできません。
function draw() { var ctx = document.getElementById('canvas').getContext('2d'); for (var i = 0; i < 10; i++){ ctx.lineWidth = 1+i; ctx.beginPath(); ctx.moveTo(5+i*14,5); ctx.lineTo(5+i*14,140); ctx.stroke(); } }
正確な線を取得するには、線の描画方法を理解する必要があります。次の図に示すように、グリッドはキャンバスの座標グリッドを表すために使用されます。各グリッドは画面上のピクセルに対応します。最初の図では、長方形 (2,1) から (5,5) までが塗りつぶされ、領域全体の境界がピクセルのエッジに正確に重なるため、結果として得られる長方形のエッジは明確になります。
(3,1)から(3,5)まで幅1.0の線を描きたい場合、2枚目の画像のような結果が得られます。実際の塗りつぶし領域 (濃い青) は、パスの両側のピクセルの半分までしか広がりません。これらの半分のピクセルは近似的な方法でレンダリングされます。つまり、これらのピクセルは部分的にのみ色付けされ、領域全体 (明るい青と濃い青) が実際のストローク カラーの半分のトーンで塗りつぶされます。上の例の幅 1.0 の線が正確でないのはこのためです。この問題を解決するには、パスをより正確に制御する必要があります。太さ 1.0 の線はパスの両側で 0.5 ピクセル延長し、3 番目の図のように (3.5,1) から (3.5,5) まで線を引くと、そのエッジが正確に落ちることがわかります。ピクセル境界にあると、塗りつぶしは正確になります。幅 1.0 の線です。幅が均一な線の場合、各辺のピクセル数が整数である場合、パスはピクセル ポイント内ではなく、ピクセル間 ((3,1) から (3,5) など) に収まるようにする必要があります。真ん中に。また、この例の垂直線の Y 座標がグリッド ライン上に正確に重なっていることに注意してください。そうでない場合は、端点に半分レンダリングされたピクセルも存在します。スケーラブルな 2D グラフィックスの操作は最初は少し面倒かもしれませんが、ピクセル グリッドとパスの位置の関係に早めに注意しておくことで、スケーリングや変形後もグラフィックスの見栄えを維持することができます。 線幅 2 倍拡大後を選択すると、幅 1.0 の縦線が幅 2.0 の明確な線になり、表示されるべき場所に表示されます。
lineCap
属性の例
属性
lineCapは、線分の端点がどのように表示されるかを決定します。バット、ラウンド、スクエアの 3 つのタイプのいずれかになります。デフォルトは尻です。
この例では、3 本の直線を描画し、それぞれに異なる lineCap 値を割り当てました。両者の違いをより明確に示すために、3 つの線の始点と終点がすべて補助線上にあります。一番左の行はデフォルトのボタンを使用します。ガイドラインと同じ高さになっていることに注目してください。中央のものは丸い効果で、線幅の半分の半径の半円が終点に追加されます。右側は正方形の効果で、幅が等しく線幅の半分の正方形が終点に追加されています。
function draw() { var ctx = document.getElementById('canvas').getContext('2d'); var lineCap = ['butt','round','square']; // Draw guides ctx.strokeStyle = '#09f'; ctx.beginPath(); ctx.moveTo(10,10); ctx.lineTo(140,10); ctx.moveTo(10,140); ctx.lineTo(140,140); ctx.stroke(); // Draw lines ctx.strokeStyle = 'black'; for (var i=0;i<lineCap.length;i++){ ctx.lineWidth = 15; ctx.lineCap = lineCap[i]; ctx.beginPath(); ctx.moveTo(25+i*50,10); ctx.lineTo(25+i*50,140); ctx.stroke(); } }
lineJoin
属性の例
lineJoin的属性值决定了图形中两线段连接处所显示的样子。它可以是这三种之一:round,bevel和miter。默认是miter。
这里我同样用三条折线来做例子,分别设置不同的lineJoin值。最上面一条是round的效果,边角处被磨圆了,圆的半径等于线宽。中间和最下面一条分别是 bevel 和 miter的效果。当值是miter的时候,线段会在连接处外侧延伸直至交于一点,延伸效果受到下面将要介绍的miterLimit属性的制约。
function draw() { var ctx = document.getElementById('canvas').getContext('2d'); var lineJoin = ['round','bevel','miter']; ctx.lineWidth = 10; for (var i=0;i<lineJoin.length;i++){ ctx.lineJoin = lineJoin[i]; ctx.beginPath(); ctx.moveTo(-5,5+i*40); ctx.lineTo(35,45+i*40); ctx.lineTo(75,5+i*40); ctx.lineTo(115,45+i*40); ctx.lineTo(155,5+i*40); ctx.stroke(); } }
miterLimit
属性的演示例子
就如上一个例子所见的应用miter
的效果,线段的外侧边缘会延伸交汇于一点上。线段直接夹角比较大的,交点不会太远,但当夹角减少时,交点距离会呈指数级增大。miterLimit
属性就是用来设定外延交点与连接点的最大距离,如果交点距离大于此值,连接效果会变成了 bevel。
渐变 Gradients
就好像一般的绘图软件一样,我们可以用线性或者径向的渐变来填充或描边。我们用下面的方法新建一个canvasGradient
对象,并且赋给图形的fillStyle或strokeStyle
属性。
createLinearGradient(x1,y1,x2,y2) createRadialGradient(x1,y1,r1,x2,y2,r2)
createLinearGradient方法接受 4 个参数,表示渐变的起点 (x1,y1) 与终点 (x2,y2)。createRadialGradient方法接受 6 个参数,前三个定义一个以 (x1,y1) 为原点,半径为 r1 的圆,后三个参数则定义另一个以 (x2,y2) 为原点,半径为 r2 的圆。
var lineargradient = ctx.createLinearGradient(0,0,150,150); var radialgradient = ctx.createRadialGradient(75,75,0,75,75,100);
创建出canvasGradient对象后,我们就可以用addColorStop方法给它上色了。
addColorStop(position, color)
addColorStop
方法接受 2 个参数,position参数必须是一个 0.0 与 1.0 之间的数值,表示渐变中颜色所在的相对位置。例如,0.5 表示颜色会出现在正中间。color参数必须是一个有效的 CSS 颜色值(如 #FFF, rgba(0,0,0,1),等等)。你可以根据需要添加任意多个色标(color stops)。下面是最简单的线性黑白渐变的例子。
var lineargradient = ctx.createLinearGradient(0,0,150,150); lineargradient.addColorStop(0,'white'); lineargradient.addColorStop(1,'black');
createLinearGradient
的例子
本例中,我弄了两种不同的渐变。第一种是背景色渐变,你会发现,我给同一位置设置了两种颜色,你也可以用这来实现突变的效果,就像这里从白色到绿色的突 变。一般情况下,色标的定义是无所谓顺序的,但是色标位置重复时,顺序就变得非常重要了。所以,保持色标定义顺序和它理想的顺序一致,结果应该没什么大问题。
第二种渐变,我并不是从 0.0 位置开始定义色标,因为那并不是那么严格的。在 0.5 处设一黑色色标,渐变会默认认为从起点到色标之间都是黑色。你会发现,strokeStyle
和fillStyle属性都可以接受canvasGradient对象。
function draw() { var ctx = document.getElementById('canvas').getContext('2d'); // Create gradients var lingrad = ctx.createLinearGradient(0,0,0,150); lingrad.addColorStop(0, '#00ABEB'); lingrad.addColorStop(0.5, '#fff'); //lingrad.addColorStop(0.5, '#26C000'); //lingrad.addColorStop(1, '#fff'); var lingrad2 = ctx.createLinearGradient(0,50,0,95); lingrad2.addColorStop(0.5, '#000'); lingrad2.addColorStop(1, 'rgba(0,0,0,0)'); // assign gradients to fill and stroke styles ctx.fillStyle = lingrad; ctx.strokeStyle = lingrad2; // draw shapes ctx.fillRect(10,10,130,130); ctx.strokeRect(50,50,50,50);
createRadialGradient
的例子
这个例子,我定义了 4 个不同的径向渐变。由于可以控制渐变的起始与结束点,所以我们可以实现一些比(如在 Photoshop 中所见的)经典的径向渐变更为复杂的效果。(经典的径向渐变是只有一个中心点,简单地由中心点向外围的圆形扩张)。这里,我让起点稍微偏离终点,这样可以达到一种球状 3D 效果。但最好不要让里圆与外圆部分交叠,那样会产生什么效果就真是不得而知了。4 个径向渐变效果的最后一个色标都是透明色。如果想要两色标直接的过渡柔和一些,只要两个颜色值一致就可以了。代码里面看不出来,是因为我用了两种不同的颜色表示方法,但其实是相同的,#019F62 = rgba(1,159,98,1)。
function draw() { var ctx = document.getElementById('canvas').getContext('2d'); // Create gradients var radgrad = ctx.createRadialGradient(45,45,10,52,50,30); radgrad.addColorStop(0, '#A7D30C'); radgrad.addColorStop(0.9, '#019F62'); radgrad.addColorStop(1, 'rgba(1,159,98,0)'); var radgrad2 = ctx.createRadialGradient(105,105,20,112,120,50); radgrad2.addColorStop(0, '#FF5F98'); radgrad2.addColorStop(0.75, '#FF0188'); radgrad2.addColorStop(1, 'rgba(255,1,136,0)'); var radgrad3 = ctx.createRadialGradient(95,15,15,102,20,40); radgrad3.addColorStop(0, '#00C9FF'); radgrad3.addColorStop(0.8, '#00B5E2'); radgrad3.addColorStop(1, 'rgba(0,201,255,0)'); var radgrad4 = ctx.createRadialGradient(0,150,50,0,140,90); radgrad4.addColorStop(0, '#F4F201'); radgrad4.addColorStop(0.8, '#E4C700'); radgrad4.addColorStop(1, 'rgba(228,199,0,0)'); // draw shapes ctx.fillStyle = radgrad4; ctx.fillRect(0,0,150,150); ctx.fillStyle = radgrad3; ctx.fillRect(0,0,150,150); ctx.fillStyle = radgrad2; ctx.fillRect(0,0,150,150); ctx.fillStyle = radgrad; ctx.fillRect(0,0,150,150); }
图案 Patterns
上一节的一个例子里面,我用了循环来实现图案的效果。其实,有一个更加简单的方法:createPattern。
createPattern(image,type)
该方法接受两个参数。Image 可以是一个Image对象的引用,或者另一个 canvas 对象。Type 必须是下面的字符串值之一:repeat,repeat-x,repeat-y
和no-repeat。图案的应用跟渐变很类似的,创建出一个 pattern 之后,赋给fillStyle或strokeStyle属性即可。
var img = new Image(); img.src = 'someimage.png'; var ptrn = ctx.createPattern(img,'repeat');
注意:与 drawImage 有点不同,你需要确认 image 对象已经装载完毕,否则图案可能效果不对的。Firefox 目前只支持属性值repeat。如果赋其它值,什么效果都没有的。
createPattern
的例子
这最后的例子,我创建一个图案然后赋给了fillStyle属性。值得一提的是,使用 Image 对象的onloadhandler 来确保设置图案之前图像已经装载完毕。
function draw() { var ctx = document.getElementById('canvas').getContext('2d'); // create new image object to use as pattern var img = new Image(); img.src = 'images/wallpaper.png'; img.onload = function(){ // create pattern var ptrn = ctx.createPattern(img,'repeat'); ctx.fillStyle = ptrn; ctx.fillRect(0,0,150,150); } }
以上就是canvas游戏开发学习之六:运用样式与颜色(二)的内容,更多相关内容请关注PHP中文网(www.php.cn)!