<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          如何使用 JavaScript 和 Canvas 創(chuàng)建星形圖案

          共 8575字,需瀏覽 18分鐘

           ·

          2021-10-02 17:09


          英文 | https://javascript.plainenglish.io/how-to-create-a-star-pattern-using-javascript-and-canvas-322f8af61ce1

          翻譯 | 楊小二


          在本教程中,我們將使用 JavaScript 和 HTML5 Canvas API 創(chuàng)建下圖橫幅的星形圖案。

          因?yàn)榧词箘?chuàng)建一顆星也需要多行代碼,所以我們將使用 drawJS——我構(gòu)建的一個(gè)處理星形渲染的迷你庫(kù)。

          在此過(guò)程中,我們將使用對(duì)象字面量、嵌套的 for 循環(huán)和余數(shù)運(yùn)算符來(lái)創(chuàng)建這種模式——以及一個(gè) CSS 媒體查詢(xún)來(lái)使橫幅在窄屏幕寬度下調(diào)整大小。

          使用 drawJS 的星形圖案演示地址:https://codepen.io/nevkatz/pen/jOmexaK

          drawStar 方法

          圖案是通過(guò)為圖案中的每個(gè)星星調(diào)用 drawJS 庫(kù)中的 drawStar 方法來(lái)創(chuàng)建的。假設(shè)我們只想創(chuàng)建圖案中的第一顆星,如下所示。

          在這種情況下,我們可以使用下面的代碼調(diào)用一次 drawStar。

          drawJS.drawStar({    cx:50,    cy:50,    numPoints:5,    stroke:'#622569',    fill:'#b8a9c9',    lineWidth:4,    innerRadius: 20,    outerRadius:35   });

          現(xiàn)在,由于我們想要?jiǎng)?chuàng)建多個(gè),因此,我們最終將編寫(xiě)一些更復(fù)雜的 JavaScript。但首先,讓我們編寫(xiě) HTML 和 CSS 并思考模式的特征。

          打好基礎(chǔ)

          讓我們從一些標(biāo)記和樣式開(kāi)始。

          HTML 和 CSS

          HTML中的<canvas> 元素。

          <canvas id="myCanvas" width="1300" height="600"></canvas>

          我們的第一個(gè) CSS 將使其成為塊元素并將其居中。

          canvas {  display: block;  margin: 10px auto;}

          為了使畫(huà)布具有響應(yīng)性,我們需要添加一個(gè)媒體查詢(xún),它將在屏幕寬度低于 1200 像素時(shí)將寬度設(shè)置為 100%。

          我們還可以使用height: auto 來(lái)幫助我們的畫(huà)布在調(diào)整大小時(shí)保持其縱橫比。

          @media screen and (max-width: 1200px) {  canvas {    width: 100%;    height: auto;   }}

          規(guī)劃模式

          在我們開(kāi)始編寫(xiě)最初的 JavaScript 之前,讓我們?cè)俅螢g覽一下星形模式并考慮制作它需要什么。

          下面是模式的前兩行。

          要以這種方式排列星星,我們需要編寫(xiě)設(shè)置幾個(gè)值的邏輯:

          • 將星星隔開(kāi)

          • 連續(xù)的星星數(shù)

          • 行數(shù)

          我們的程序還需要設(shè)置每顆星星的獨(dú)特屬性,包括以下內(nèi)容:

          • 點(diǎn)數(shù)

          • 描邊顏色

          • 填充顏色

          星星還有一些共同的特性:

          • 邊界寬度

          • 內(nèi)半徑,或恒星中心到每個(gè)角的距離

          • 外半徑,或從恒星中心到每個(gè)外點(diǎn)的距離

          最后,我們需要設(shè)置以下內(nèi)容:

          • 第一顆星的位置

          • 筆觸和填充顏色的調(diào)色板(每種四種顏色)

          • 最小和最大星點(diǎn)數(shù)

          由于這是一種模式,因此應(yīng)該定期重復(fù)變化的星形屬性。例如,你會(huì)注意到點(diǎn)數(shù)從 5 開(kāi)始,然后從一顆星到下一顆增加 1,直到達(dá)到 12 點(diǎn)。一旦發(fā)生這種情況,下一位明星將獲得 5 分。

          這些是我們需要轉(zhuǎn)換為代碼的模式屬性。

          設(shè)置模式屬性

          現(xiàn)在我們已經(jīng)概述了模式的要求,讓我們卷起袖子,用兩個(gè)函數(shù)編寫(xiě)它的邏輯:

          • getPatternProps,它建立星形圖案的屬性。

          • init,它將遍歷每個(gè)星星的位置,設(shè)置每個(gè)星星的屬性,并調(diào)用 drawJS.drawStar 方法。

          getPatternProps 函數(shù)將返回一個(gè)包含我們模式屬性的對(duì)象。

          function getPatternProps() {     let patternProps = {        start: {            x: 50,            y: 50,        },        numPoints: {            min: 5,            max: 12        },        space: {            x: 100,            y: 100        },        count: {            x: 12,            y: 6        },        fills: ['#b8a9c9', '#98d1d6', '#fed8b1', '#cff7d5'],        strokes: ['#622569', '#4C858A', '#f06d06', '#008000']    };  return patternProps;}

          讓我們來(lái)看看發(fā)生了什么:

          • start 將第一顆星的 x 和 y 坐標(biāo)設(shè)置為 (50,50)。

          start: { x:50, y:50 }
          • numPoints 將使星星可以擁有的最少點(diǎn)數(shù)設(shè)為 5,并將最大點(diǎn)數(shù)設(shè)置為 12。

          numPoints: { min:5, max:12 }
          • space 將使星星在垂直和水平方向上相距 100 像素。

          space: {x: 100, y: 100 }
          • count 告訴我們?cè)谝恍?(x) 和六行 (y) 中有 12 顆星。

          count: { x: 12, y: 6}
          • fills 將確定作為重復(fù)序列出現(xiàn)的四種填充顏色。

          fills: ['#b8a9c9', '#98d1d6', '#fed8b1', '#cff7d5']
          • 筆畫(huà)以相同的方式工作,使用數(shù)組來(lái)設(shè)置星形邊框顏色的重復(fù)序列。

          strokes: ['#622569', '#4C858A', '#f06d06', '#00ff00']

          啟動(dòng)我們的 init 函數(shù)

          我們的 init 函數(shù)將執(zhí)行以下操作:

          • 設(shè)置圖案的背景顏色

          • 檢索模式屬性

          • 遍歷每個(gè)星位置

          • 設(shè)置每顆星的屬性

          • 為每個(gè)星星調(diào)用 drawJS.drawStar

          讓我們啟動(dòng)我們的 init 函數(shù)并調(diào)用 setBackground,一個(gè)用于設(shè)置畫(huà)布背景顏色的 drawJS 方法。

          function init() {   drawJS.setBackground('#215875');}

          此 setBackground方法使用 Canvas API 的 rect 和 fill 方法,并且是你將在庫(kù)中看到的第一個(gè)方法。

          現(xiàn)在,我們有了背景顏色,讓我們通過(guò)調(diào)用 getPatternProps 來(lái)獲取星形圖案的屬性。

          function init() {   drawJS.setBackground('#215875');   let props = getPatternProps();}

          設(shè)置循環(huán)

          在我們的 init 函數(shù)中,讓我們創(chuàng)建一個(gè)填充星星的嵌套循環(huán)。我們將逐步建立這個(gè)。

          讓我們首先遍歷行。我們可以使用 props.count.y 值訪問(wèn)行數(shù)。

          let props = getPatternProps();for (var y = 0; y < props.count.y; ++y) {}

          現(xiàn)在讓我們看看 props.count.x 中每行的星星數(shù)。

          for (var y = 0; y < props.count.y; ++y) {   for (var x = 0; x < props.count.x; ++x) {   }}

          我們現(xiàn)在擁有的這些 x 和 y 索引將派上用場(chǎng)。

          這是我們的 init 函數(shù)的開(kāi)始:

          function init() {    // set background on canvas    drawJS.setBackground('#215875');
          // get star properties let props = getPatternProps();
          // loop through rows for (var y = 0; y < props.count.y; ++y) {
          // loop through stars in a row for (var x = 0; x < props.count.x; ++x) {
          } }}

          好的,這是 init 函數(shù)的一個(gè)很好的開(kāi)始。到目前為止,我們已經(jīng)設(shè)置了我們的背景顏色,定義了我們的圖案屬性,并設(shè)置了我們的循環(huán)。

          確定每個(gè)星星的位置

          在這個(gè)嵌套循環(huán)中,讓我們想象一下它正在繪制的當(dāng)前星星。要確定這顆星星的位置,它必須使用 props 中的 start 和 space 屬性。

          我們的目標(biāo)是計(jì)算恒星的中心坐標(biāo)并將它們存儲(chǔ)在兩個(gè)變量中:cx 和 cy。

          讓我們從星星的左上角位置開(kāi)始:props.start.x 和 props.start.y。那是在橫幅的左上角,第一顆星星的中心所在。

          接下來(lái),讓我們找出每顆星星相對(duì)于第一顆星星的位置應(yīng)該在哪里。這取決于它在序列中的位置(x 和 y)以及星間距(props.space.x 和 props.space.y)。

          要找出離第一個(gè)位置有多遠(yuǎn),讓我們將當(dāng)前的 x 或 y 索引乘以相應(yīng)的空間值。

          props.space.x * xprops.space.y * y

          下面的表達(dá)式將 props.start.x 添加到 props.space.x 和 x 的乘積,給我們當(dāng)前恒星的水平位置。

          let cx = props.start.x + props.space.x * x;

          這個(gè)表達(dá)式以同樣的方式為我們提供了垂直位置。

          let cy = props.start.y + props.space.y * y;

          我們現(xiàn)在可以獲得每顆恒星的中心。

          找出每顆星星的點(diǎn)數(shù)

          在模式中,點(diǎn)數(shù)增加,直到達(dá)到 12。之后,我們回到 5。然后我們?cè)俅伍_(kāi)始增加。但是我們?nèi)绾未_定每顆星星上的點(diǎn)數(shù)呢?為了找到這個(gè),我們首先需要知道每個(gè)恒星在序列中的位置。

          如果我們把整個(gè)模式看作一個(gè)數(shù)組,這個(gè)位置可以看作是星星的索引。

          尋找明星指數(shù)

          下面你可以看到每個(gè)星星的索引在模式的前兩行中應(yīng)該是什么。

          我們可以在循環(huán)外聲明一個(gè)計(jì)數(shù)器變量并每次遞增它,但讓我們用數(shù)學(xué)方法找到索引,以便我們可以更多地探索這些 x 和 y 值。

          讓我們首先找到當(dāng)前星星所在行上方的行數(shù),即 y。現(xiàn)在讓我們將 y ,先前行的數(shù)量,乘以 props.count.x,每行的星星數(shù)。

          y * props.count.x

          如果我們當(dāng)前的星星在第三排呢?

          • 我們知道 props.count.x 總是 12。

          • 在我們的第三行中,y 是 2。

          • 所以上面幾行的星星數(shù)是 12 ? 2 = 24。

          然后我們應(yīng)該添加 x,它是當(dāng)前行中先前星的數(shù)量。然后我們可以用這個(gè)方程定義 star_idx。

          let star_idx = x + props.count.x + y;

          尋找點(diǎn)的范圍

          當(dāng)我們從一顆星到下一顆時(shí),我們希望點(diǎn)數(shù)從 5 增加到 12,然后從 5 重新開(kāi)始并重復(fù)。

          要知道何時(shí)從 5 點(diǎn)重新開(kāi)始,我們必須知道我們可以擁有多少個(gè)不同的點(diǎn)數(shù)。所以讓我們找出最小點(diǎn)數(shù)和最大點(diǎn)數(shù)之間的范圍,包括 5 和 12。

          在代碼中,我們將稱(chēng)其為 diff。

          let diff = props.numPoints.max - props.numPoints.min + 1;

          由于 star.numPoints.max 是 12 并且 star.numPoints.min 是 5,因此在這種情況下 diff 最終為 8。

          使用余數(shù)運(yùn)算符

          現(xiàn)在讓我們找出每顆星星的點(diǎn)數(shù)。每顆星至少有五分,但有些可能有更多分。

          為了計(jì)算出還有多少,我們將使用 num、星級(jí)索引和我們剛剛計(jì)算的差異。我們使用余數(shù)運(yùn)算符來(lái)查找將 num 除以 diff 所得的余數(shù)。

          let morePoints = num % diff;

          morePoints 可以得到的最高值是 7。例如,15 除以8,我們將 15 除以 8 得到的余數(shù)是 7。如果我們?cè)黾拥?16,那么 16 除以8 會(huì)重置為零。以下是兩行中這種重復(fù)增加的情況:

          為了獲得當(dāng)前星星上的點(diǎn)數(shù),我們?nèi)?morePoints 并添加最小點(diǎn)數(shù)——props.numPoints.min——即 5。

          let numPoints = props.numPoints.min + morePoints

          以下是兩行中點(diǎn)數(shù)的外觀:

          萬(wàn)歲!已找到每顆星上的點(diǎn)數(shù)。

          使星星變小

          為了使星星變小,讓我們放置一個(gè)從 1 開(kāi)始但在每行之后逐漸變小的乘數(shù)。

          let multiplier = (props.count.y - y) / props.count.y;

          因?yàn)槲覀兊男兴饕?y 從零開(kāi)始,props.count.y — y 在我們的第一行中是 6 — 0 或 6。

          結(jié)果,props.count.y — 1 / props.count.y = 6/6 = 1。

          但在第二行,y 是 1。

          所以 props.count.y — y 是 6 — 1 或 5。

          因此,如果我們四舍五入到最接近的百分位,props.count.y — 1 / props.count.y = 5/6 = 0.83。

          我們現(xiàn)在可以使用乘數(shù)來(lái)調(diào)整星星的外半徑和內(nèi)半徑,我們將分別初始化為 35 和 20。

          let outerRadius = 35, innerRadius = 20;

          現(xiàn)在讓我們用乘數(shù)改變每一個(gè)。

          outerRadius *= multiplier;innerRadius *= multiplier;

          完整的乘法器邏輯如下所示:

          查找顏色、線寬和旋轉(zhuǎn)

          現(xiàn)在我們想要一個(gè)重復(fù)的顏色模式。請(qǐng)記住,我們有四種筆觸顏色和四種填充顏色,正如我們?cè)?stars 對(duì)象中的數(shù)組中所指定的:

          fills: ['#b8a9c9', '#98d1d6', '#fed8b1', '#cff7d5'],strokes: ['#622569', '#4C858A', '#f06d06', '#008000']

          為了確定填充和筆畫(huà),我們將再次使用余數(shù)運(yùn)算符,但這一次是為了確定筆畫(huà)和填充數(shù)組中應(yīng)該有什么索引,我們將假設(shè)它們具有相同的長(zhǎng)度。我們將此值稱(chēng)為 color_idx。

          let color_idx = num % props.fills.length

          我們的 props.fills 數(shù)組的長(zhǎng)度為 4,它成為我們的除數(shù)——所以我們可能的余數(shù)值在 0 到 3 之間。

          為了獲得填充和描邊,我們使用 color_idx 索引到每個(gè)數(shù)組。

          let fill = props.fills[color_idx];let stroke = props.strokes[color_idx];

          一旦一顆星星用數(shù)組中的最后一種顏色渲染,程序就會(huì)為下一顆星星使用第一種顏色。

          最后,讓我們?cè)O(shè)置 lineWidth 和rotate,這對(duì)每個(gè)星星都是一樣的:

          const lineWidth = 4, rotate = 0;

          至此,我們需要的所有屬性都已經(jīng)設(shè)置好了!

          回顧

          讓我們回顧一下我們現(xiàn)在擁有的九個(gè)屬性。

          • cx 和 cy 是恒星中心點(diǎn)的坐標(biāo)。

          • externalRadius 和innerRadius 決定了恒星的大小。

          • 填充和描邊是星星的顏色。

          • 每顆星的線寬和旋轉(zhuǎn)保持不變。

          • LnumPoints 確定每顆星上的點(diǎn)。

          現(xiàn)在讓我們將所有這些打包成一個(gè)對(duì)象,并將其直接傳遞給 drawStar 方法。

          drawJS.drawStar({     cx,     cy,     outerRadius,     innerRadius,     numPoints,     lineWidth,     stroke,     fill,     rotate});

          由于每個(gè)鍵的名稱(chēng)都與其在該對(duì)象中的值相同,因此我們可以對(duì)鍵和值使用一個(gè)術(shù)語(yǔ)——例如,cx 代替 cx:cx,rotate 代替rotate:rotate。

          這是完成的 init 函數(shù)的樣子。

          function init() {    // set background on canvas    drawJS.setBackground('#215875');
          // get star properties let props = getPatternProps();
          // loop through rows for (var y = 0; y < props.count.y; ++y) {
          // loop through columns for (var x = 0; x < props.count.x; ++x) {
          // determine star's center position let cx = props.start.x + props.space.x * x; let cy = props.start.y + props.space.y * y;
          // determine number of points let star_idx = x + props.count.x * y; let diff = props.numPoints.max - props.numPoints.min + 1; let morePoints = star_idx % diff; let numPoints = props.numPoints.min + morePoints;
          // determine star size let multiplier = (props.count.y - y) / props.count.y let outerRadius = 35, innerRadius = 20; outerRadius *= multiplier; innerRadius *= multiplier;
          // determine star color let color_idx = star_idx % props.fills.length; let fill = props.fills[color_idx]; let stroke = props.strokes[color_idx];
          // determine linewidth and rotation const lineWidth = 4, rotate = 0;
          // call the method drawJS.drawStar({ cx, cy, outerRadius, innerRadius, numPoints, lineWidth, stroke, fill, rotate }); } // end inner loop } // end outer loop}

          就是這樣!這就是代碼。下面是我們的演示,因此,你可以看到所有內(nèi)容如何組合在一起。

          查看演示地址:https://codepen.io/nevkatz/pen/jOmexaK

          總結(jié)

          恭喜你!到這里已完成本教程,你已經(jīng)成功地使用了許多 JavaScript 概念以及相當(dāng)多的數(shù)學(xué)來(lái)創(chuàng)建這個(gè)星形圖案。如果你想了解這方面的更多信息,以下是我建議的一些后續(xù)步驟:

          • 修改 getPatternProps 以便你可以想出不同的模式。

          • 嘗試為一顆星星制作動(dòng)畫(huà)——然后嘗試將多顆星星排列成一個(gè)圖案。

          • 嘗試使用 Math.random() 和一些模式修改來(lái)創(chuàng)建夜空。

          • 希望你能從我的這篇文章中學(xué)會(huì)用 JavaScript 和 Canvas 繪制星星。

          謝謝閱讀!


          學(xué)習(xí)更多技能

          請(qǐng)點(diǎn)擊下方公眾號(hào)

          瀏覽 40
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产成人视频在线观看 | 欧美草逼大全 | 欧洲在线观看 | 人人摸人人艹人人骑 | 北条麻妃被两个黑人玩 |