2021年4月23日 星期五

p5.js 學習筆記 (六) : 重複的圖形

過去一周為了進入動態圖形測試複習了 Javascript 語法, 用了這麼久的 Javascript 卻從來沒好好整理過筆記, 趁這機會溫習一下也不錯. 本篇是學習 p5.js 動態圖形之前的暖身, 測試如何用迴圈與分支語法來繪製重複的圖形. 

本系列之前的文章參考 : 


以下測試使用之參考文件 : 

https://p5js.org/reference/ (教學文件)
https://editor.p5js.org (線上編輯器)

Javascript 教學文件參考 :


繪製重複的圖形主要是靠迴圈, 最常用的是 for 迴圈語法 :

for (var i=初始值; i 的條件式; 更新 i 的值) {
    //繪圖敘述
    }

例如 :

for (var i=0; i<100; i++) {  //i 遞增 1
    line(i, 0, i, 100);
    }

或者 :

for (var i=0; i<100; i += 10) {  //i 遞增 10
    line(i, 0, i, 100);
    }

迴圈中可用 if~else 語句控制繪製與否. 


1. 繪製重複的線段 : 

之前在畫直線時採用坐標列舉法逐一填入各線段的起始與終點坐標來繪製, 但如果要繪製具有重複現象的線段, 光是確定坐標值就很費功夫了, 其實這種規則性的圖形可利用迴圈來簡化程式碼與提高程式可讀性, 例如 :



<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="cache-control" content="no-cache">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <title>p5.js test</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.min.js"></script>
</head>
<body>
  <script>
    function setup() {
      createCanvas(200, 100);      
      background(200, 200, 200);
      stroke('blue');
      }
    function draw() { 
      for(var i=0; i<19; i++){   //繪製 19 條垂直線
        line(10 + i*10, 0, 10 + i*10, 100);   //每條線間隔 10 px
        }
      }
  </script>
</body>
</html>

此例在 200*100 的畫布上繪製 19 條垂直線, 因不含兩邊故為 20-1=19, 迴圈從 0 迭代至 18, 第一條線為 (10, 0, 10, 100), 最後一條為 (190, 0, 190, 100), 結果如下 :



 
如果間隔 10px 畫上水平線即可變成方格 (grid), 例如 :



<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="cache-control" content="no-cache">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <title>p5.js test</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.min.js"></script>
</head>
<body>
  <script>
    function setup() {
      createCanvas(200, 100);      
      background(200, 200, 200);
      stroke('blue');
      }
    function draw() { 
      for(var i=0; i<19; i++){
        line(10 + i*10, 0, 10 + i*10, 100);    //繪製 19 條垂直線
        if (i<9) {
          line(0, 10 + i*10, 200, 10 + i*10);  //繪製 9 條水平線
          }        
        }
      }
  </script>
</body>
</html>

此例在上面的垂直線基礎上加上一個 if 分支, 當迭代變數 i 小於 9 時繪製水平線, 因為畫布 y 座標最大為 100, 上下邊線不畫則應畫 9 條線 (i=0~8). 水平線基本上就是將垂直線的 (x, y) 對調, 但是終點的 x 座標是 200, 結果如下 :




只要控制 line(x1, y1, x2, y2) 的座標變數便可以繪製斜線, 例如 : 


測試 1-3 : 繪製斜線 (1) [看原始碼]  

<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="cache-control" content="no-cache">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <title>p5.js test</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.min.js"></script>
</head>
<body>
  <script>
    function setup() {
      createCanvas(200, 100);      
      background(200, 200, 200);
      stroke('blue');
      }
    function draw() { 
      for(var i=20; i<180; i += 20) {  
        line(i, 20, i + 20, 80);    //繪製斜線
        }
      }
  </script>
</body>
</html>

此例透過迴圈變數 i=20~180, 每次遞增 20, 控制線條起始坐標的 x 與終點坐標的 y (向右延伸 20px) 繪製斜線, 結果如下 :




控制坐標增減可繪製左右斜線, 例如 :


測試 1-4 : 繪製斜線 (2) [看原始碼]  

<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="cache-control" content="no-cache">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <title>p5.js test</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.min.js"></script>
</head>
<body>
  <script>
    function setup() {
      createCanvas(200, 100);      
      background(200, 200, 200);
      stroke('blue');
      }
    function draw() {
      var cnt=0;
      for(var i=20; i<200; i += 20){
        if(cnt < 8) {   //最後一條左斜線不畫
          line(i, 20, i + 20, 80);
          }
        if(cnt > 0 ) {   //第一條右斜線不畫
          line(i, 20, i - 20, 80);
          }
        ++cnt;
        }
      }
  </script>
</body>
</html>

此例透過變數 cnt 控制第一條右斜線與最後一條左斜線不畫繪製柵欄圖形, 結果如下 :




下面是繪製斜率漸變直線的範例 :



<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="cache-control" content="no-cache">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <title>p5.js test</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.min.js"></script>
</head>
<body>
  <script>
    function setup() {
      createCanvas(200, 100);      
      background(200, 200, 200);
      stroke('blue');
      }
    function draw() {
      for(var i=0; i<200; i += 10){
        line(i, 0, 1.5*i, 100);      //利用 > 1 倍的終點 x 坐標改變斜率
        }
      }
  </script>
</body>
</html>

此例利用終點 x 坐標的倍數控制直線的斜率, 倍數越大越傾斜, 結果如下 :




下面範例是兩條線段的組合 :



<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="cache-control" content="no-cache">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <title>p5.js test</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.min.js"></script>
</head>
<body>
  <script>
    function setup() {
      createCanvas(200, 100);      
      background(200, 200, 200);
      stroke('blue');
      }
    function draw() {
      for(var i=0; i<200; i += 10){
        line(i, 0, 1.5*i, 50);          //第一條線段
        line(1.5*i, 50, i, 100);      //第二條線段
        }
      }
  </script>
</body>
</html>

此例兩條線段在畫布中央 (y=50) 相連, 第二條的終點坐標 (i, 100) 向左折回 i 形成 > 的圖形, 調整折回程度 (例如改為 1.2*i, 100) 或中央相接點 (例如 y=40) 都可以改變圖形, 結果如下 : 




2. 繪製重複的圓 : 

在迴圈中繪製重複的圓也可以製作出繁複的圖樣, 主要是利用迴圈不斷移動圓心或直徑, 例如 :



<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="cache-control" content="no-cache">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <title>p5.js test</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.min.js"></script>
</head>
<body>
  <script>
    function setup() {
      createCanvas(200, 120);      
      background(200, 200, 200);
      noStroke();
      }
    function draw() {
      var r=20;   //半徑
      for(var x=0; x<=width; x += 2*r){  //圓心 x 軸每次向右移一個直徑
        fill('navy');                 //填滿色彩
        circle(x, 0, 2*r);         //y 軸第一個圓
        circle(x, 2*r, 2*r);      //y 軸第二個圓
        circle(x, 4*r, 2*r);      //y 軸第三個圓
        circle(x, 6*r, 2*r);      //y 軸第四個圓
        }
      }
  </script>
</body>
</html>

此例使用一層 for 迴圈循 x 軸向右移動來繪製圓形, 每次迴圈在 y 軸上繪製 4 個圓 (不重疊 y 坐標向下增量一個直徑, 0, 2r, 4r, 6r), 注意, 為了剛好能在 y 軸放入三個圓, 畫布的高度調整為 120px, 結果如下 :




事實上這個圖案也可以用兩層 for 迴圈來做, 程式會更簡潔, 例如 : 



<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="cache-control" content="no-cache">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <title>p5.js test</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.min.js"></script>
</head>
<body>
  <script>
    function setup() {
      createCanvas(200, 120);      
      background(200, 200, 200);
      noStroke();
      }
    function draw() {
      var r=20;
      for(var x=0; x<=width; x += 2*r){     //第一層 : 圓心 x 軸座標
        for(var y=0; y<=height; y +=2*r){   //第二層 : 圓心 y 軸座標
          fill('tomato');
          circle(x, y, 2*r);    //繪製圓形
          }
        }
      }
  </script>
</body>
</html>

此例使用兩層迴圈來繪圖, 迴圈中只要呼叫一次 circle() 即可, 與上例一次畫四個 y 軸方向的圓不同, 此處是先沿著 x 軸一個一個畫, 再沿著 y 軸往下畫, 結果與上例一樣 (僅顏色不同) : 




下面是我在書上看到的一個輻射的圓範例加以改寫 : 


測試 2-3 : 繪製重複的圓 (3) [看原始碼]

<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="cache-control" content="no-cache">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <title>p5.js test</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.min.js"></script>
</head>
<body>
  <script>
    function setup() {
      createCanvas(400, 300);      
      background('cyan');
      }
    function draw() {
      for(var x=20; x<=width-20; x += 20){
        for(var y=20; y<=height-20; y +=20){
          stroke(102, 102, 102, 50);      //設定線條透明度避免右半面覆蓋圓之效應太明顯
          line(x, y, width/2, height/2)    //畫布中心至圓心之直線
          stroke('black');  
          fill('white');          
          circle(x, y, 10);
          }
        }
      }
  </script>
</body>
</html>

此例使用兩層迴圈在最內層先畫圓再畫一條連接畫布中心至圓心的直線, 由於當 x >= width/2 之後圓會被其他的線覆蓋, 因此設定線的透明度來避免覆蓋太明顯, 結果如下 :




沒有留言 :