Canvas描繪多彩的星星 | HTML5圖形開發 從最基礎開始學Canvas(二):基本圖形變換、狀態的保存恢復及代碼實現五角星

本文已參與好文召集令活動,點擊查看:後端、大前端雙賽道投稿,2萬元獎池等你挑戰!javascript

基本代碼以下,全部示例在此canvas實現前端

<style>
    canvas{
        border: 1px solid #000;
    }
</style>

<canvas width="600" height="500" id="c1"></canvas>
    <script> let canvas=document.getElementById("c1"); let ctx=canvas.getContext("2d"); // 示例。。。 </script>
複製代碼

基本的圖形變換

基本的圖形變換包括位移、旋轉、縮放。在canvas中,這些操做都是基於座標系原點進行操做的。在複雜多圖形處理中,不一樣的圖形應用的變換多種多種,這樣就有可能產生混亂,所以Canvas中提供save和restore方法,實現座標系、顏色設置等上下文的隔離和還原。java

位移(translate)

  • translate(x, y): 移動 canvas 的原點到指定的位置。即移動的是座標原點
ctx.beginPath();
// 將canvas座標系原點移動到 x,y
ctx.translate(origin.x,origin.y);
ctx.arc(0,0,20,0,2*Math.PI);
ctx.fillStyle="green";
ctx.fill();

ctx.beginPath();
ctx.rect(-canvas.width/2 +100,-canvas.height/2+50,200,100);
ctx.strokeStyle="red";
ctx.stroke();
複製代碼

旋轉(rotate)

  • rotate(angle):順時針方向的,以弧度爲單位旋轉座標軸,旋轉的中心是座標原點canvas

    旋轉(座標原點)後端

let rotateTest=function(){
    ctx.beginPath();
    ctx.rotate(Math.PI/180*30);
    ctx.rect(0,0,320,180);
    ctx.fillStyle="green";
    ctx.fill();
}
rotateTest();
複製代碼

  1. 移動並旋轉
let rotateTest2=function(){
    // 位移原點,旋轉時以原點旋轉
    ctx.translate(100, 100);

    ctx.beginPath();           
    ctx.rect(0, 0, 320, 180);
    ctx.fillStyle = "red";
    ctx.fill();

    ctx.beginPath();
    ctx.rotate(Math.PI/180*32);
    ctx.rect(0,0,320,180);
    ctx.fillStyle="green";
    ctx.fill();
}
rotateTest2();
複製代碼

縮放(scale)

  • scale(x, y) 經過增減圖形在 canvas 中的像素數目,對形狀(位圖)進行縮小或者放大。

​scale方法。x,y分別表示橫軸和縱軸的縮放,正值。小於1表示縮小,大於1表示放大,1爲原始比例。數組

默認狀況下,canvas 的 1 單位就是 1 個像素。舉例說,若是咱們設置縮放因子是 0.5,1 個單位就變成對應 0.5 個像素,這樣繪製出來的形狀就會是原先的一半。同理,設置爲 2.0 時,1 個單位就對應變成了 2 像素,繪製的結果就是圖形放大了 2 倍。markdown

能夠看做縮放是整個畫布座標系的縮放app

let scaleTest=function(){
    ctx.beginPath();
    ctx.strokeStyle="green";
    ctx.lineWidth=3;
    ctx.strokeRect(0,0,200,100);

    // 縮放x或y軸
    ctx.scale(2,1);
    ctx.scale(1,2);
    ctx.scale(2, 2);
    ctx.beginPath();    
    ctx.strokeStyle = "red";
    ctx.lineWidth = 3;
    ctx.strokeRect(0, 0, 200, 100);
}
scaleTest();
複製代碼

兩點間的距離

以下,利用勾股定理求距離dom

let getDistance=function(x1,y1,x2,y2){
    return Math.sqrt(Math.abs((x1 - x2) * (x1 - x2))*Math.abs((y1-y2)*(y1-y2)))
}
複製代碼

sin\cos\tan\atan2函數

數學中sin-正弦、cos-餘弦、tan-正切的關係以下圖:函數

  • Math.sin(x) 返回一個 -1 到 1 之間的數值,表示給定角度(單位:弧度)的正弦值。
  • Math.cos(x) 返回一個 -1 到 1 之間的數值,表示角度(單位:弧度)的餘弦值。
  • Math.atan2(y,x) 返回從原點(0,0)到(x,y)點的線段與x軸正方向之間的平面角度(弧度值),返回值-pi 到 pi 之間,點x,y的偏移角度。Math.atan(y/x)返回的弧度在一三或二四象限是相同的,沒法區分。
  • Math.tan(x) 返回一個角(弧度)的正切值。`

// sin cos atan2
let sincosatan2Test=function(){
    let p={
        x:100,
        y:100,
    }

    let alpha=Math.atan2(p.x,p.y);
    console.log(`座標${p.x},${p.y}的弧度值:${alpha}`);
    console.log(`座標${p.x},${p.y}的角度:${alpha*180/Math.PI}度`);
    let anglePI_sin=Math.sin(Math.PI);
    let anglehalfPI_sin=Math.sin(Math.PI/2);
    let angle2PI_sin = Math.sin(Math.PI*2);
    let angle1000_sin = Math.sin(1000);
    console.log("PI的sin:"+anglePI_sin);
    console.log("1/2PI的sin:"+anglehalfPI_sin);
    console.log("2*PI的sin:"+angle2PI_sin);
    console.log("1000的sin:"+angle1000_sin);

    let anglePI_cos = Math.cos(Math.PI);
    let anglehalfPI_cos = Math.cos(Math.PI / 2);
    let angle2PI_cos = Math.cos(Math.PI * 2);
    let angle1000_cos = Math.cos(1000);
    console.log("PI的sin:" + anglePI_sin);
    console.log("1/2PI的sin:" + anglehalfPI_sin);
    console.log("2*PI的sin:" + angle2PI_sin);
    console.log("1000的sin:" + angle1000_sin);
}
sincosatan2Test();
複製代碼

Canvas狀態的保存與恢復

在Canvas中,Saving and restoring state是繪製複雜圖形時必不可少的操做。

save的做用在於隔離出來一個新的canvas上下文環境,保存以前的狀態,能夠從新設置新的樣式並繪製圖形;restore的做用在於恢復上一次的保存的狀態,使用舊的樣式繪製。

尤爲是對於使用了位移、旋轉、縮放等效果的狀況下,restore能夠還原座標系的狀態,防止複雜操做下出現混亂

save()restore()方法用來保存和恢復Canvas的狀態

Canvas的狀態就是當前畫面應用到的全部樣式和變形的一個快照

save()

Canvas狀態存儲在棧中,每當save()方法被調用後,當前的狀態就被推送到棧中保存。

一個繪畫狀態包括:

  • 當前應用的變形(即移動,旋轉和縮放)

  • strokeStyle, fillStyle, globalAlpha, lineWidth, lineCap, lineJoin, miterLimit, shadowOffsetX, shadowOffsetY, shadowBlur, shadowColor, globalCompositeOperation 的值

  • 當前的裁切路徑(clipping path)

能夠調用任意屢次save方法。(相似數組的push())

restore()

每一次調用restore方法,上一個保存的狀態就從棧中彈出,全部設定都恢復。(相似數組的pop())。

save和resotre對canvas上下文狀態的隔離和管理很是方便,一般寫canvas效果能夠以下所示:

// 保存以前的狀態
ctx.save();
// 樣式設置
//...
ctx.restore();//恢復狀態
複製代碼

save和restore使用示例

以下,使用這個過程:畫一個正方形,保存以前的狀態並修改顏色繪製,保存以前的狀態並修改顏色繪製,恢復狀態並繪製,恢復狀態並繪製,繪製的一個小例子。

// 狀態保存恢復
let statusSaveRestore=function(){
    ctx.fillRect(0, 0, 150, 150);   // 使用默認設置繪製一個矩形
    ctx.save();                  // 保存默認狀態

    ctx.fillStyle = 'red'       // 在原有配置基礎上對顏色作改變
    ctx.fillRect(15, 15, 120, 120); // 使用新的設置繪製一個矩形

    ctx.save();                  // 保存當前狀態
    ctx.fillStyle = '#FFF'       // 再次改變顏色配置
    ctx.fillRect(30, 30, 90, 90);   // 使用新的配置繪製一個矩形

    ctx.restore();               // 從新加載以前的顏色狀態
    ctx.fillRect(45, 45, 60, 60);   // 使用上一次的配置繪製一個矩形

    ctx.restore();               // 加載默認顏色配置
    ctx.fillRect(60, 60, 30, 30);   // 使用加載的配置繪製一個矩形
}
statusSaveRestore();
複製代碼

不使用狀態保存和恢復的效果以下:

多種多樣的五角星示例

以下,五角星的五個尖角和5個鈍角能夠看做從圓心平均分開的10個點,能夠由內外兩個圓各自包含5個點,給定不一樣的內外圓的半徑,各個點的座標就能夠經過正餘弦求得。

以下,實現五角星的函數代碼,還能夠修改,防止產生反五角星:

// 畫一個五角星
let drawPentagram=function(options){

    let ctx=options.ctx;
    let origin = {
        x: options.x,
        y: options.y
    }
    let lengthScale=options.lengthScale||0.4; // 大於1也是五角星 反五角星

    // 五角星長短邊
    let lengthR = options.lengthR||100;
    let shortR = lengthScale* lengthR;
    // 五角星的角度 弧度
    let starRotate=options.starRotate||0;
    let strokeColor=options.strokeColor||"red";

    let deg = Math.PI * 2 / 10;

    
    ctx.save();
    // 移動畫布原點到五角星中心
    ctx.translate(origin.x, origin.y);
    // 先假設長邊角 位於x軸上
    // 旋轉座標系,x軸向上,即尖角向上,保證擺正五角星
    ctx.rotate(- Math.PI / 2);

    ctx.rotate(starRotate);

    ctx.beginPath();
    //ctx.moveTo(lengthR*Math.cos(0),lengthR*Math.sin(0));
    ctx.moveTo(lengthR, 0);
    for (let i = 1; i < 10; i++) {
        let currDeg = i * deg;
        if (i % 2 === 0) { //lengthR
            ctx.lineTo(lengthR * Math.cos(currDeg), lengthR * Math.sin(currDeg));
        }
        else {
            ctx.lineTo(shortR * Math.cos(currDeg), shortR * Math.sin(currDeg));
        }
    }
    ctx.closePath();
    ctx.strokeStyle = strokeColor;
    ctx.stroke();
    // 將座標系旋轉放正 旋轉的是座標系,之前已經畫好的圖形保持不變
    // 由於使用了restore,此處的旋轉還原能夠省略
    // ctx.rotate(Math.PI / 2);
    ctx.restore();

}
複製代碼

畫一個標準的五角星:

drawPentagram({
    ctx, 
    x:canvas.width / 2, 
    y:canvas.height / 2,
});
複製代碼

代碼效果以下:

隨機產生無數星星:

let colorArr=["red","greed","yellow","pink","olive","blue","orange","brown","purple"]

for (let i = 0; i < 10; i++) {
    drawPentagram({
        ctx,
        x: canvas.width*Math.random(),
        y: canvas.height*Math.random(),
        lengthR:100*Math.random(),
        lengthScale: Math.random(),
        strokeColor:colorArr[Math.floor(colorArr.length*Math.random())],
        starRotate: Math.PI*2* Math.random()
    });
}
複製代碼

代碼效果以下:

相關文章
相關標籤/搜索