網頁 彙整 | Creative Coding TW - 互動程式創作台灣站 https://creativecoding.in/tag/網頁/ 蒐集互動設計案例、教學與業界資源,幫助你一起進入互動程式創作的產業 Sat, 17 Jul 2021 15:15:32 +0000 zh-TW hourly 1 https://wordpress.org/?v=6.2.2 https://creativecoding.in/wp-content/uploads/2022/03/cropped-cct-logo-icon-2-32x32.png 網頁 彙整 | Creative Coding TW - 互動程式創作台灣站 https://creativecoding.in/tag/網頁/ 32 32 使用Vue.js建立一個sass色票卡視覺化網頁(直播筆記) https://creativecoding.in/2021/06/25/%e4%bd%bf%e7%94%a8vue-js%e5%bb%ba%e7%ab%8b%e4%b8%80%e5%80%8bsass%e8%89%b2%e7%a5%a8%e5%8d%a1%e8%a6%96%e8%a6%ba%e5%8c%96%e7%b6%b2%e9%a0%81/ Fri, 25 Jun 2021 02:28:00 +0000 https://creativecoding.in/?p=1124 寫網頁的時候,單看sass變數的程式碼,會不知道色碼是不是合適的嗎?老闆帶你一小時就能利用Vue.js快速建立好視覺化色票卡小工具。文章會從一開始雛型的設計稿發想,一步步教你如何完成工具。

這篇文章 使用Vue.js建立一個sass色票卡視覺化網頁(直播筆記) 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>
不知道大家有沒有以下經驗?網頁切版時,需要使用 sass 變數所建立的顏色,但是程式裡面只看到一堆色碼,卻沒辦法立即看到自己所選的變數顏色到底是不是需要的顏色。

老闆這次要帶大家做個小工具來解決這個問題,在開發時間有限的狀況下,利用工具輸入顏色變數名稱與色碼,透過產出的每一張色卡便能夠快速選擇需要的變數名稱與色碼。文章會從一開始雛型的設計稿發想,到最後使用 Vue.js 來完成工具。

想看著影片跟著老闆動手做,請到這邊,也附上這次成品

這次直播筆記會帶大家學會以下內容:

  • 開發專案前使用 PS, 與 Adobe XD 雛型發想的訣竅
  • 使用 Vue 進行畫面資料綁定、Vue 的資料再處理
  • 利用 Vue component,製作色卡元件

事前準備

老闆會先帶大家利用 PS 與 Adobe XD 規劃出成品雛型,如果大家沒有這些設計工具,可以使用老闆規劃的雛型進入開發,接著會說明 codepen 開發環境的設定。

規劃 UI

執行專案前,老闆習慣先使用 photoshop 初步構思成品,來做為草稿使用,你也可以隨手拿起一張白紙與一支筆,畫出你的草稿。

這次的畫面主要分為兩個部份,左邊的輸入框提供我們填寫 sass 顏色變數,右邊則為色卡,每一張色卡上面為顏色,下面則是色卡的標題與色號。開發時,就能利用這個工具找到需要的顏色,直接複製顏色變數使用。

Photoshop草稿
Photoshop草稿

下面跟大家介紹一個工具 – Adobe XD,可以快速建立想像的畫面,做雛型時,會希望文字或群組間的間距平均分布, Adobe XD 會貼心地跳出平均分布的提示。另外將圖片文字群組後,可以使用 repeat grid 快速製造多份。此外,拉出來的每個色卡可以各別調整名字,微調色卡文字位置時,其他色卡的文字也會跟著移動。若是一次拖曳多張圖片到 Adobe XD 中,能夠在每張色卡上,顯示不同的圖片。如果有興趣的話大家可以去下載試用版玩玩。

AdobeXD 圖稿
AdobeXD 圖稿

開發環境

這次開發使用 codepen 線上撰寫程式碼,大家可以先將環境設定成跟老闆一樣,如果想知道較詳細的設定,可以到成品這邊看老闆的設定。

  • html 使用 pug
  • css
    • 使用 Sass
    • 引用 twitter-bootstrap,要注意引用進來的版本不同,有些語法不通用
  • js 引用 2.1.10/vue.min.js

接下來會使用到的 API:

這次會使用到較多的 api,大家可以跟著老闆操作,比較能夠了解每個 api 使用時機,以下簡單介紹。

Html – bootstrap

由於老闆在這個專案使用到的是第四版的 bootstrap ,大家在使用上要注意自己引用的版本,這邊附上第四版 bootstrap 的文件

  • .container:bootstrap layout 最基本的容器,提供格線系統的操作。
  • .row:bootstrap 中 layout 的行。
  • .col-sm-4 欄:bootstrap 中 layout 的欄。包覆在最內層,在 sm 這個斷點內,這一個位置會占 4/12,12 是 bootstrap預設每行的欄數,那剩下的空間就是 .col-sm-8。

javascript, Vue

  • 使用 Vue 的方式如下,el 為要綁定的範圍,data 內為要綁定的資料們,computed 可以理解為資料再處理,會自動將值重新組裝換算後回傳。
// javascript
var vm = new Vue({
  el: "#app",
  data: {...},
  computed: {...}
})
  • Vue 資料綁定
    • {{name}}:在 html 內容,若是有雙花括的出現,裡面的名字會與 Vue 中 data 對應的 key 值替代。
    • v-model :另一種綁定資料的方式,若是在 input, textarea 等可填寫的 tag 中使用,則可以同步修改 Vue 中綁定的資料。
    • v-bind:使用 v-bind 來將資料綁定到 tag 中的指定屬性上,可以簡寫為 ” : ” 。
  • Vue Component:可以將 html 做成元件 template 重複使用,在 template 上面使用 id=”colorcard” 來宣告,並在 js 中進行註冊,註冊方式先給予元件名稱,再傳入對應的物件值。要使用時只要傳入對應的資料,就能讓元件使用傳入的值 props ,渲染出對應的元件。此外,component 也同樣能使用自己的 computed 屬性。
// html
colorcard(:card="card")

template#colorcard
// javascript
// 註冊元件名稱, 物件
Vue.component('colorcard', {
  // 引用的結構來源
  template: '#colorcard',
  // 傳入的資料
  props: ['card'],
  data: {},
  computed: {}
})
  • js api
    • String.split(‘\n’):使用指定的方式作為規則(‘\n’),切分成許多小字串的物件。連結
    • Array.push(物件):將物件加到 Array 中的最後一個。連結
    • .indexOf(條件):檢查字串或陣列,是否符合條件,如果有就回傳位置,沒有則回傳 -1。連結

跟著老闆開始動手做

基礎 html 結構樣式與 Vue 資料綁定

在資料綁定前,我們先進行畫面的切版。.container 要加上 #app 的原因,是因為後續我們要使用 Vue,這個 id 是為了提供 Vue 去抓作用的範圍。如果在使用 bootstrap 不確定自己的 div 佔據多少位置,可以在 css 內用 * 字號的類別選擇器,為所有 tag 加上 border,以便開發時了解佈局。

// html
.container#app
  h1 sass 變數色卡網頁工具{{name}}
  // hr 水平線
  hr
  .row
    .col-sm-4
      textarea
    .col-sm-8
      .colorcard
// css
*
  border: 1px solid 
textarea
  width: 100%
  height: 400px

新增一個 Vue,監視這裡面有哪些資料是要代換的,寫法如下:

大家可以發現 html 中的 {{name}} 馬上被 data 中的 name 取代,替代成 Codepen了,這就是畫面資料與 Vue 的資料綁定。

// javascript
var vm = new Vue({
  el: "#app",
  data: {
    name: "Codepen"
  }
})

textarea 資料雙向綁定色碼變數

現在遇到一個問題,我們要如何將一長串的色碼變數綁定到 Vue 中呢?

首先我們先在 Vue data 中新增一個 key 值 colorsetting,並將 textarea 的值貼進去,這時候會發現一個問題,程式報錯了。這是因為在 javascript 中,字串直接用換行會出錯,我們只要將複製進來的整串的色碼與色碼之間加上”\n”就可以將 textarea 的值變成一串字串。

這時我們想到,不可能每次都手動將顏色變數名稱和色碼加入到 data 中,希望能達成在畫面中的 textarea 新增資料後會同步到 Vue data 中,這時我們會使用到 Vue 雙向綁定資料方式 v-model。

我們可以先在 html 畫面中新增一個 p tag ,使用雙花括來綁定資料,做為資料內容的顯示。接著將 textarea 後面加上 v-model,這時再去試試看調整 textarea 中的資料,上面 p tag 的內容是不是也跟著變了呢?

// html
...
  .col-sm-4
    //顯示全部字串
    p {{colorsetting}}
    //單一色碼一行顯示
    textarea(v-model="colorsetting")
...
// javascript
var vm = new Vue({
  el: "#app",
  data: {
    name: "Codepen",
    colorsetting: "//顏色變數\n$color_black: #303030\n$color_bg: #F7F0E9\n$color_berry: #D56134\n$color_top: #9C4215\n$color_md_1: #F3D1BA\n$color_md_2: #F7E1CD\n$color_bottom: #773000\n$color_cherry_1: #FF613A\n$color_cherry_2: #DF5333"
  }
})

第一張色卡

在一次製作所有色卡前,我們來製作第一張色卡,來複習前面的資料綁定。首先先在 Vue 裡面新增一組變數 color_card,裡面包含三個內容,顏色變數名稱 name、色碼 colorcode、顏色樣式 colorcss,colorcss 待會會拿來與 .block 綁定樣式,要注意的是,Vue 的 key 值如果要使用到 “-” ,需要用雙引號將這個 key 值包住,直接改成小駝峰的方式也支援。

html 的部份我們為右邊的色卡區快新增了一個 div .colorcard ,裡面包含 .block 顯示顏色,以及 .info 顯示色卡的變數名稱 .name 與色碼 .code 並且分別綁定,這邊使用到雙花括之外,遇到了一個新的綁定方式 v-bind,這是 tag 中屬性的綁定方式,我們這邊用來綁定樣式 style,可以寫成 v-bind:style=””,或是 :style=””。而在css 的內容,因為我們要顯示顏色,所以先將 .block 撐出一個高度。

// javascript
...
data: {
 ...
  color_card: {
    name: '$color_berry',
    colorcode: '#D56134',
    colorcss: {
      "background-color": '#D56134'
      //或另一種寫法 backgroundColor: '#D56134'
    }
  }
}
// html
...
.col-sm-8
  .colorcard
    .block(:style="color_card.colorcss")
    .info
      .name {{color_card.name}}
      .code {{color_card.colorcode}}
// css
.block
  height: 300px

處理 textarea 字串

有了第一個色卡,接下來就要將 textarea 內的字串,變成多組一樣的資料格式,該怎麼處理呢? 在 Vue 中有一個屬性 computed,可以幫我們把資料進行再計算或處理。

讓我們先帶大家做個小模擬了解 computed 的作用,首先我們在 data 中新增一個變數 price,另外使用 computed 新增一個 nameprice,他會回傳一個值是由 price 與 TWD 組成,將這些值綁定到畫面後,結果就會如圖所示,這個後處理除了加字串外,還有很多地方可以應用,例如幫 price 加上折扣數。

// html
.container#app
  .price {{price}}
  .nameprice {{nameprice }}
// javascript
...
data: {
  price: 100
},
computed: {
  nameprice: function () {
    return this.price + "TWD"
  }
}

了解 computed 的作用後,接下來我們使用 computed 來將 textarea 內的 colorsetting 字串變成一組組的 color_card色卡格式,並用陣列存起來。

刪除了剛剛的小模擬之後,首先我們先在 computed 內建立一個新的 key 值,首先建立一個空陣列,先利用將 .split(‘\n’) 將 colorsetting換成一整組陣列。接著用 for 迴圈去針對這個陣列裡面的所有值去處理,使用 .split(‘:’) 取得變數名稱,改用空白去取得色碼,這邊要小心的是,因為 color 是用空白去分割字串,輸入到 textarea 的格式都要是”$變數名稱: 色碼”,冒號與色碼間要保留空白,否則在取得顏色色碼時會出錯。

取到 name 與 color 後,依照我們剛剛第一組色卡的資料格式,組出新的色卡物件後使用 push 加到 result 中。完成後就可以將前面的 html 綁定資料調整一下,色卡們就這樣出現了。

// javascript
data: {
...
},
computed: {
  colorcards: function () {
    var result = []
    var cut_string = this.colorsetting.split('\n')
    for(var i=0; i<cut_string.length; i++){
      var name = cut_string[i].split(':')[0]
      var color = cut_string[i].split(' ')[1]
      result.push({
        name: name,
        colorcode: color,
        colorcss: {
          "background-color": color
        }
      })
    }
    return result
  }
}
// html
...
.col-sm-8
  ul.row
    li.col-sm-3(v-for="card in colorcards")
      .colorcard
        .block(:style="card.colorcss")
        .info
          .name {{card.name}}
          .code {{card.colorcode}}

過濾不符合色卡格式的內容

想必大家已經發現奇怪的地方,為什麼標題也跟著加入了?如果輸入的資料不符合色卡的資料格式怎麼也顯示?沒錯,接下來我們就要再加工,讓 colorcards 回傳的內容能夠先篩掉不符合資料格式的內容。這邊我們示範變數名稱不符合規定要被篩掉的方式,大家如果有想到其他更嚴謹的篩選方式都可以實驗看看。

// javascript
...
colorcards: function () {
  var result = []
  var cut_string = this.colorsetting.split('\n')
  for(var i=0; i<cut_string.length; i++){
    var name = cut_string[i].split(':')[0]
    var color = cut_string[i].split(' ')[1]
    if (name.indexOf('color') != -1) {
      result.push({
        name: name,
        colorcode: color,
        colorcss: {
          "background-color": color
        }
      })
    }
  }
  return result
}

調整樣式

接下來就是收尾階段,將畫面美化,這邊我們總共會調整以下幾點:

html 部分

  • 拿掉綁定的 p {{colorsetting}}
  • 調整每張色卡的 col 欄數為 col-sm-4
// html
.container#app
  h1 sass 變數色卡網頁工具{{name}}
  hr
  .row
    .col-sm-4
      textarea(v-model="colorsetting")
    .col-sm-8
      ul.row
        li.col-sm-4(v-for="card in colorcards")
          .colorcard
            .block(:style="card.colorcss")
            .info
                .name {{card.name}}
                .code {{card.colorcode}}

css 部分 – 以下是老闆調整出來的最終樣式,大家也可以按照自己喜好去做調整。

  • 取消所有的 border
  • 增加 body 的 padding-top
  • 左邊 textarea 增加內距、行高、字距
  • 取消右邊色卡區塊的 ul 內距與 li 的 list-style
  • 每張色卡增加圓角、陰影、超出的部分隱藏
  • 色卡互動,增加 hover 效果、 transition 與游標笑果
  • 色卡內距:要注意調整內距時。寬度增加可以使用 box-sizing: border-box,意思是將框限與內距也算在寬度內。
  • 色卡資訊內距、文字顏色與粗細;色票號碼字級縮小,因為使用這個工具時,主要是要顏色的變數名稱,色碼不是必要的資訊。
// css
body
  padding-top: 50px

textarea
  width: 100%
  height: 400px
  padding: 10px
  line-height: 30px
  letter-spacing: 1px

ul
  list-style: none
  padding: 0
  
.colorcard  
  border-radius: 5px
  background-color: white
  overflow: hidden
  box-shadow: 0px 0px 10px rgba(black,0.2)
  transition: 0.5s
  cursor: pointer
  
  &:hover
    transform: translate(-5px,-5px)
  
  .block
    height: 100px
    
  .name
    font-size: 15px
    font-weight: bold
  .code
    font-size: 12px
    color: rgba(black,0.4)
    
  .info
    padding: 5px

li
  padding: 5px

Vue component

最後老闆帶大家認識一下 Vue強大的功能之一:元件 (Component),它可以將部分模板、程式碼封裝起來,以便開發者維護或重複使用。以這次專案為例子,色卡是重複的元件,所以我們來練習將色卡做為 component。

除了將原本 colorcard 的 html 結構改寫成 template#colorcard 外,我們也需要在 javascript 中註冊 colorcard 的元件,註冊的方式如下,component 也擁有自己的 computed 屬性,大家可以利用這個屬性來做其他的資料再處理。註冊完畢時,在對應的位置使用這個註冊好的元件名稱,傳入對應的資料。

使用 component 來改寫這些程式碼的好處,除了可以再處理資料外,也讓資料綁定畫面時,不用宣告這麼長的名稱 card.name 與 name2 的差異,閱讀上明顯清楚很多。

// html
...
  li.col-sm-4(v-for="card in colorcards")
    // 使用註冊的元件,並傳入所需的值
    colorcard(:card="card")
...      
template#colorcard
  .colorcard
    .block(:style="card.colorcss")
    .info
      .name {{name2}}
      .code {{card.colorcode}}
// javascript

Vue.component('colorcard', {
  template: '#colorcard',
  props: ['card'],
  data: {},
  computed: {
    name2: function () {
      return this.card.name
    }
  }
})

快速回顧

首先讓我們快速回顧一下,使用 Vue.js 開發 sass 色票工具的流程:

  1. 利用 PS 與 Adobe XD 規劃成品雛型
  2. 基礎 html 結構樣式與了解 Vue 資料綁定
  3. textarea 資料雙向綁定色碼變數
  4. 完成第一張色卡後,將資料綁定到色卡中
  5. 利用 computed 製作出所有色卡,並過濾不符合的資料
  6. 調整樣式
  7. 使用Vue component 改寫每一張色卡

萬事起頭難,一個作品不可能一步到位,將最終目標拆分成不同階段任務,從一開始的雛型慢慢開發出每個區塊,最後組裝在一起。透過這次的主題,讓大家能了解 Vue 框架,並發現它畫面資料綁定的方便。完成的作品如果能改善實務工作流程,肯定是一舉兩得,也可以透過自己實際使用後再回頭優化自己的作品。

如果你喜歡老闆的這些教學資源,歡迎加入老闆開的課程中一起學習,順便支持一下老闆,課程會帶你看看不一樣的作品,並引導大家一步步完成作品,透過每次的賞析、實作到修正作品,讓大家覺得寫 code 不是這麼難的事情,將這個過程想像成,拿一隻比較難的畫筆在進行創作,如果有機會使用它,便能夠在網頁上做出與眾不同的創作。

老闆的互動網頁課程

動畫互動網頁程式入門(HTML/CSS/JS)以簡單例子帶你入門網站的基礎架構及開發,用素材刻出簡單有趣又美觀的網頁和動畫,享受做出獨一無二的網頁所帶來的成就感,在職場上與設計師和工程師合作無間。

打好基本的互動網頁基礎之後,可以進階動畫互動網頁特效入門(JS/CANVAS),紮實掌握JavaScript 程式與動畫基礎以及進階互動,整合應用掌控資料與顯示的Vue.js前端框架,完成具有設計感的互動網站。期待在課程裡見到你!

墨雨設計banner

這篇文章 使用Vue.js建立一個sass色票卡視覺化網頁(直播筆記) 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>
從不只是一門線上課程,而是一場推動進化的豪賭 https://creativecoding.in/2021/06/16/%e5%be%9e%e4%b8%8d%e5%8f%aa%e6%98%af%e4%b8%80%e9%96%80%e7%b7%9a%e4%b8%8a%e8%aa%b2%e7%a8%8b%ef%bc%8c%e8%80%8c%e6%98%af%e4%b8%80%e5%a0%b4%e6%8e%a8%e5%8b%95%e9%80%b2%e5%8c%96%e7%9a%84%e8%b1%aa%e8%b3%ad/ Wed, 16 Jun 2021 03:07:00 +0000 https://creativecoding.in/?p=986 墨雨設計創辦人,也是互動藝術家的吳哲宇,於2016年第一堂線上課程「動畫互動網頁程式入門」上架後的一個月,撰寫下初衷、籌備的歷程以及實踐後的成就感,與你分享。

這篇文章 從不只是一門線上課程,而是一場推動進化的豪賭 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>

本文撰寫時間為2016/10/2,由墨雨設計創辦人,同時也是互動藝術家的吳哲宇親筆記錄下關於「動畫互動網頁程式入門」這堂線上課程的來龍去脈,從最開始的起心動念、一路的辛苦籌備路程,還有被越來越多的學生上了幾堂課後的作業所驚豔,更加堅定地相信設計跨領域程式、以及各領域的雜學所能帶給世界的創新能量,並且願意帶著後起之秀一同前進,持續推動互動領域(無論是網頁、科技、設計乃至於藝術產業)的發展。

在課程上線滿一個月的這天,啜著咖啡看到人數已逐漸來到了1667人,整理著每天到三四點睡留下來的瓶瓶罐罐跟咖啡杯,試圖留下些什麼紀錄,回神才發現準備課程這段漫長的道路已接近了尾聲,便打起了草稿想把這一切曲折離奇、燃燒生命的光芒記下

「寫網頁好難喔….每次看線上程式教學,都在講解功能沒講怎麼完成一個好看的網頁,總覺得自己做出來,離別人美美的網站就是有一段沮喪的距離」

我想,這句話是當初開始想開課的初衷,也是自己三年前開始踏入網頁領域自學的痛,總覺得無法掌控的各種超自然力量在影響網頁的排版,各種摸不清底細的屬性,總要擺兩包科學麵獻祭祈禱網頁乖乖的不要跑掉,光是用工程師思維把網站寫出來都很吃力了,更別提要如何處理視覺、文字,讓網頁不會看起來陽春的像小學電腦課做的。

三年前第一次接網頁案子
三年前第一次接網頁案子(再之前做網頁是國中flash時代了…)

那時候第一次網頁還是脫離不了所見及所得軟體,要改東西直接拖拉,用adobe animate不顧結構做出一個還算可以用的網站,心想,做網站不過就如此嘛,我幹嘛那麼辛苦去寫html跟css,尤其當那時html只知道可以放元素,css只知道改改文字顏色改改框線的時候。

波折的三年有很多奇怪的案子

經過了波折的三年,接了數十個專案的歷練跟學習下來:

  1. 從單純的html/css,開始踏入js、踏入各種svg/canvas動畫效果
  2. 一開始接觸bootstrap之後狂用,但受限於風格跟不易改動後又捨棄,那時功力還沒有辦法秒速做到bootstrap水準。
  3. 逐漸用很基本的css/Jquery 也能夠做出很漂亮精準的互動,開始不喜歡用別人的套件,用自己理解到的原理或概念重建parallax網站或互動
  4. 開始研究物件結構跟演算法製作動態跟互動的網頁,愛上優雅的物件結構跟定義,把重力、3D、生物、遊戲等等概念濃縮到網頁上。
  5. 因為要做售票系統跟會員開始入門後端php跟資料庫,到中期為了給客戶編輯自幹了一套還算不錯用的CMS,在這個時期建立了完整前後端的概念,體驗到了溝通問題也體驗到接案的窘境。
  6. 摸過laravel/ruby on rails幾個月,覺得有趣但模板一半切完板之後交給後端處理,改動的可能性就消失了,回到原本輕型框架的網頁結構。
  7. 寫了一年後發現資料在後端處理跟產生網頁真的太麻煩,觸碰到了前端框架angular.js/ Vue.js,愛上了用資料轉換網頁的樂趣,從快速變成極快速,尤其Vue.js的調性真的很簡潔大方。
  8. 開始集大成,把手邊能用的技術逐漸都熟練,開始把實踐的功能寫成一個個模組,比如自動分析列表產生音波文字,用後期分析的方式,以canvas為基礎動態產生靈活的動畫,操作聲音、數學,覺得網頁真的可能性無限。
  9. 更加熟悉資料流/前端的互動,專案在規畫的時候會更全盤地思考如何在既有的架構跟畫面下創造更多可能性,讓網頁活起來,或是有個觸動心靈的點,甚至看到有趣可以實驗的案例就直接用網站實現出來(像是示波器)。

這些年來很多有趣的案例:

生活中很多有趣的案例都可以當作網頁的素材,所以對我而言,網頁是一種呈現媒介,很有力量跟可能性的呈現媒介,第一個:他快,可以迅速的把東西/產品上架/測試實驗性的想法,第二個:他會動,比起靜態的呈現,互動感會帶給我們很大的感受升級,第三個:他跨平台,只要有瀏覽器就有網站。

其他的範例可以到 hahow課程頁面 或我的codepen觀看。

「恩..說是要分享,但是要從哪裡開始呢?」

5月時,與hahow的魏敏討論市場上網頁技術的需求之後,決定開設一門讓大家可以輕鬆入門網頁,卻又不像是一般codeacademy / 一些免費的教學,只能大概了解概念,卻沒有辦法有系統地完成一個網頁跟調整視覺。

線上課程HAHOW平台

討論完之後,終於訂出了這次課程精準的目標,說是精準其實也有點惶恐,是一個大方向,很少人嘗試過的教學方式:

「我想要用設計的角度去教程式(恩?」

因此將課程的目標定為「用illstrator的概念了解並實作網頁」,並且每一個範例是貨真價實的,帶著把一個網頁從頭刻到尾,會碰到甚麼問題/要調整哪些css/視覺的考量如何轉換成程式的架構…等,比起怎麼做,更重視 「想要達成甚麼效果」跟「為什麼要這樣做」,才不會讓東西過於枯燥。

原本的大綱規劃有十三堂課,分別講解html基礎概念到css到帶入一些js的基礎概念,想說畢竟是”入門”課程嘛,就是每一個會用到的東西大概帶到就ok了:

///原本的課程規劃
1 - html/css/js 網站結構介紹- 一棵三種語言構成的大樹
2 - 規劃架構- 寫網頁前的規劃與準備
3 - 元素定位- 基礎元素定位 上下左右對齊與大小
4 - 基礎html/css - 網頁名片
5 - 開始開發- 架構原則- 使用 class 與 id 操作元素
6 - 開始開發- Codepen操作實務- 介紹sass與jade 快速開發入門
7 - 元素定位- padding、margin、align 元素之間彼此的關係
8 - 元素定位- div布局策略、overflow 有最好的棋盤才能下最好的棋
9 - 視覺介面- css 初階視覺調整
10 - 視覺介面- 顏色、大小、一切你在Illstrator會看到的美好事物
11 - 視覺介面- 字體 小小改變就能帶來超高CP值的調整
12 - 視覺介面- Illstrator 圖像匯入與png實用
13 - 靜態專案實作-實作模仿刻一個HAHOW的課程頁面
14 - 使用者互動- css 動畫-滑鼠的點擊、進入、滑動互動
15 - 使用者互動-基礎 css animation使用 用%影格概念操作動畫
16 - JS 基礎入門 - 使用Jquery改變元件外觀
17 - JS 基礎入門 - 使用Jquery 在各種事件中觸發網頁動態改變
18 - SVG - 向量不失真的網頁圖像格式
19 - SVG 動畫 - 讓你的LOGO或圖像動起來
20 - 動態專案實作- 做一個獨特動態的個人頁面
21 - 破除障礙- 問題解決與找資源的技巧
22 - 後續發展- 兩大路線 (前端網頁佈局/ 專攻動畫與圖形處理)

「錯了,錯了,全部都錯了」

隨著湧入的人越來越多,我一開始錄的時候發現,完全不是這麼回事啊!!!

如果稀哩呼嚕一堂講了兩個小時,誰聽得懂你在做甚麼,尤其當教學的東西到一個量之後沒有任何練習範例或看得到的產出,看的人就會開始覺得無趣抽象,抓不到你想傳述的概念,更別提去練習或了解了,這種教學方式,就像是拿著一本說明書一樣對著學生在念嘛,自己看著都覺得無趣了,更別提怎麼讓別人愉悅地把東西學進去。

想了好久好久,決定來進行一次大改造,想像自己如果是平面設計師,完全沒有程式基礎的時候,會怎麼樣去了解一個東西,為什麼要這樣做那樣做呢,到底什麼樣的範例事會讓大家覺得有趣的? 什麼才能讓大家再做中學,學中獲得成就感呢?

也因此課程暴增到了九十幾堂,每一堂原本預計5~10分鐘,但也時常超過20分鐘甚至到一個小時,就為了把最完整的思考流程、設計等等脈絡帶出來,才算是好的教學,想像自己是一個完全的新手,對於網站開始要有了解,有了全面的認知之後,再開始進入開發階段,一個個把小小的工具跟技能練好實作,再一個階段一個階段地把看似不可能的專案實踐出來,在小成就感中喜悅,逐漸成長。

Project 2 品牌視覺管理-使用sass/jade管理開發
///新的課程列表
 1 - 最新公告區(2016/9/28)-點擊"講義"查看最新課程消息
 2 - 楔子-課程進行模式說明 
 3 - 楔子-網頁前後端如何運作 
 4 - 基礎前期規劃-網站專案開發流程 
 5 - 基礎前期規劃-網站主題名稱logo 
 6 - 基礎前期規劃-網站瀏覽結構樹規劃 
 7 - 基礎前期規劃-網站排版規劃與分類 
 8 - 基礎前期規劃-網站視覺配色概念與資源 
 9 - 本機環境架設 - sublime 操作與瀏覽器預覽網頁 
 10 - 本機環境架設 - 伺服器瀏覽與原理講解 
 11 - Codepen環境架設 - 平台介紹/註冊與基礎設定 
 12 - Codepen環境架設 - 實際使用sublime中快速鍵 
 13 - 基礎HTML/CSS - html中元素&排列的概念 
 14 - 基礎HTML/CSS - html中結構&層級的概念 
 15 - 基礎HTML/CSS - <project 0> 簡易版本自我介紹 
 16 - 基礎HTML/CSS - css 直接調整外觀與顏色框線 
 17 - 基礎HTML/CSS - css 分開撰寫 - class&id概念 
 18 - 基礎HTML/CSS - css 顯示方式 display block/inline 
 19 - 基礎HTML/CSS - css 元素位置 - 相對 / 絕對定位 
 20 - 基礎HTML/CSS - css 內間隔/外間隔(padding/margin) 
 21 - 基礎HTML/CSS - css 字體變化與span-在文章段落中製作變化 
 22 - 基礎HTML/CSS - <project 1> html / css 大整合-製作獨特名片網頁 
 23 - ​基礎HTML/CSS - <homework 1> 功課說明-製作自己的技能網頁 
 24 - 系統性管理開發 - html縮寫模組-Emmet 介紹 
 25 - 系統性管理開發 - html樣板語言-jade (課程主要使用) 
 26 - 系統性管理開發 - css 樣板語言-sass (課程主要使用) 
 27 - 系統性管理開發 - sass - 變數概念管理色彩&內容 
 28 - 系統性管理開發 - sass - 動態產生模組mixin概念 
 29 - 系統性管理開發 - sass - 常用mixin與累積資源 
 30 - 系統性管理開發 - html參考資料轉換jade 
 31 - 系統性管理開發 - <project 2> 實作網頁品牌視覺指導套色 
 32 - 素材前期準備 - 如何在以拉中製作icon/圖像 
 33 - 素材前期準備 - 如何輸出圖片jpeg/png/svg 
 34 - 素材前期準備 - 將圖片上傳到imgur影像網站 
 35 - 素材前期準備 - 管理網頁色彩(guideline/sass/js) 
 36 - 前端基礎動畫互動-html attr 與自定義屬性名稱 
 37 - 前端基礎動畫互動 - css 綜合定位運用 absolute / relative 
 38 - 前端基礎動畫互動 - css 加入基礎滑鼠互動 :hover / :active 
 39 - 前端基礎動畫互動 - css 動畫基礎 transition-duration/delay 
 40 - 前端基礎動畫互動 - css 製作影格動畫 animation/keyframes 
 41 - 前端基礎動畫互動 - css 動畫速度曲線 fillmode/speed curve 
 42 - 前端基礎動畫互動 - SVG - 繪製向量網頁圖片 / logo 
 43 - 前端基礎動畫互動 - SVG - 讓你的LOGO或圖像動起來 
 44 - 前端基礎動畫互動 - <project 3> 動態互動天氣盒子 
 45 - 前端進階程式js-引言 
 46 - 前端進階程式js - jquery 動態改變css外觀/ html內容 
 47 - 前端進階程式js - jquery 初階滑鼠事件 - click/hover 
 48 - 前端進階程式js - jquery 變數概念- 儲存修改與判斷 
 49 - 前端進階程式js - json 物件陣列概念 & for 遍歷 
 50 - 前端進階程式js - jquery / json 動態產生購物車清單 
 51 - 前端進階程式js - Jquery ajax - 非同步載入與應用介紹 
 52 - 前端進階程式js - Jquery ajax - 實作導入資料代辦清單 
 53 - 前端進階程式js - <project 4> 實作購物車-動態新增購買物品與結算 
 54 - RWD原理與應用-內容流與概念說明 
 55 - RWD原理與應用-指定比例尺寸% 與max-width/min-width 
 56 - RWD原理與應用-重新排版的原理-特定條件css-media query 
 57 - RWD原理與應用-實作手機版面-模仿fb帳號頁面桌面/手機板變化 
 58 - RWD原理與應用-懶人工具- bootstrap 原理與結構講解 
 59 - RWD原理與應用-bootstrap 格線系統(container/row/column)原理 
 60 - RWD原理與應用-bootstrap 欄(xs/sm/md/lg) RWD應用 
 61 - RWD原理與應用-bootstrap 應用技巧 padding型規劃/多層div 
 62 - <project 5> 實際應用範例 bootstrap-常見企業品牌網頁 
 63 - 網頁視覺設計-流程-版面規劃軟體 AI/SKETCH/紙筆 
 64 - 網頁視覺設計-流程-與頁面結構/跳轉方式規劃 
 65 - 網頁視覺設計-元素-樣式 顏色規劃 
 66 - 網頁視覺設計-元素-元素動畫 反應規劃 
 67 - 網頁視覺設計-元素-從元素建構而上的設計 
 68 - 網頁視覺設計-元素-從頁面整體切分而下的設計 
 69 - 網頁視覺設計-元素-從設計轉換程式網頁的常用技巧 
 70 - <project 6> 實際網站應用案例-Material Design風UI/UX 
 71 - 前端框架Vue.js-為什麼要用資料導向做網頁(回顧js) 
 72 - 前端框架Vue.js-將變數代入模板中 
 73 - 前端框架Vue.js-v-for 列舉元素應用 
 74 - 前端框架Vue.js-v-model 使用者輸入雙向綁定 
 75 - 前端框架Vue.js- v-if / v-show 條件渲染與資料的後處理-實作博客來 
 76 - 前端框架Vue.js- v-on / method 建立js事件 
 77 - 前端框架Vue.js-與AJAX的對接 動態載入資訊 
 78 - 前端框架Vue.js-綜合案例-使用hahow課程資料 
 79 - <project 7> 客製化待辦清單Todo List 
 80 - 購買伺服器部署/網域-伺服器原理與規格說明 
 81 - 購買伺服器部署/網域-購買linux主機與網址DNS設置 
 82 - 購買伺服器部署/網域-購買不能ssh連線的主機設置 
 83 - 購買伺服器部署/網域-安裝apache/mysql 
 84 - 購買伺服器部署/網域-使用filezilla軟體連線與上傳 
 85 - 購買伺服器部署/網域-使用sublime sftp進行同步 
 86 - <project 7> 購買伺服器部署/網域-網站上線實作 
 87 - 實作案例分析-HAHOW-練習使用Bootstrap+Vue.js建構課程頁面 
 88 - 實作案例分析-Autodesk-影片式背景一頁式網頁+導覽列 
 89 - 實作案例分析-Medium-部落格-多資料首頁 
 90 - 破除障礙- 問題解決與找資源的技巧 
 91 - 後續發展- 兩大路線 (前端網頁佈局/ 專攻動畫與圖形處理)

我知道列表看起來有點長有點可怕,但是每個單元都是5–10分鐘(後期常超過20…),一個功能一個功能帶入並詳細地分析、演示這會用在真正寫網頁的哪些地方,帶著實作一次,也因為方法、結構都是一整套下來,照著思路練習過幾次,自然就能逐漸熟悉網頁撰寫的流程。

如果以前有人這樣帶著我這樣有趣的入門網頁,應該就可以少雷的一兩年的人了吧(笑,有些自己探索了很久去蕪存菁的重點,也是在時間歷練之下理出的心法,所以我不後悔做這樣的決定,更是與有榮焉希望有朝一日如果看到設計師們漸漸地不再懼怕程式,不管是溝通、還是台灣網頁界的現況都能夠得到極大的成長。

「每個人都是在雷人中成長,磨利了現在的自己,那為什麼要讓大家再自己坎坷的走一遍?」

曾經有一個建築廠商找我,希望能夠製作一個工地管理系統,方便能夠把工人的位置/狀態回報/或是建材等等的資訊,以一個APP或是網頁的方式呈現,在建材需要的數量/報價上也能夠及時掌握數量跟回報,他們長期以來的人事都是email傳excel檔案管理,亂糟糟的毫無章法,更常漏東漏西或時間成本全砸在上面。

這是非常好的改變,但是一個晚上他打電話來,說他不想做了,因為不管怎麼做都沒有辦法防止有心人士看到系統,然後直接請工程師團隊模仿一個出來,他說:

「這樣不就自己花了錢來讓競爭對手變厲害嗎? 我幹嘛這樣做」

然後就憤憤不平地掛電話了,當下我是十分錯愕的,談好已經幾乎要開始執行的案子突然就沒了。

但是更令我沮喪的是,他們寧可用各種複雜的excel報表,有時差地傳遞資料/手動計算,而不願意試圖改良前進,即使對手也許會看到跟進這樣的制度,台灣的傳統廠商到底發生了什麼問題,為什麼當我們踩穩了一個能夠賺錢跟成長的位置之後就放棄了進化呢?

同樣的道理套用在我的課程上,有很多人跟我說:那是你的專業耶!你捨得這樣掏心掏肺地把課程設計得像蛋糕一樣容易吸收,把大量的經驗分享出去!?你不怕別人這樣學完之後就變成你的競爭對手嗎?

我們不願意進步,恐懼別人進步,因為潛意識知道自己沒在前進。

課程錄製中大量的砲灰,大概三分之一

有有趣的對手交流較勁比自己獨鬥有趣,更何況,誰說我一輩子要靠這個吃飯,難道會寫網頁賺錢之後就要死命地抱著自己僅有的一點點技能嗎?我從來都沒有放棄前進,放棄學習,也因此在課程中學到的儘管多,也僅僅是過去的我的巔峰,一轉眼又再成為遠方的背影。

雖然這陣子錄課程錄到回台北過家門而不入XD(喂,大量的不讀不回別人訊息XD 好多好多時間都砸在這個上面,還是真的很開心的,當然不是要催大家看,影片一直都會在,只希望你記得你曾經想學習,就不會忘記初衷。

「一場豪賭 一場自我進化」

台灣現況

在傳統的職場環境(台灣)中,設計師被稱作是美工,不過我想這雙方都有一點問題,一個是設計師被動地認為自己是接收工作並且直接執行美感轉換,像是一個人體Photoshop一般的存在,所以在面對不合理的修改要求、抱怨的時候會怨天尤人,心情也差了,但還是認命地改,不企圖反駁什麼,畢竟台灣社會從小到大的教育並不鼓勵我們表達想法,多得是你就照我說的做就對了的心態。

那時候做Remy Martin的APP介面設計做超久,無限的修改…

設計做到後期之後反而覺得真正重要的是「溝通」,比起美感,不管怎麼樣的風格都有它美的極限;在不同風格間,並非誰比較好,而是誰比較適合這個載體資訊。網頁的本質是溝通媒介,所以當溝通的訊息沒有成功的傳遞,不管UI再絢麗再細緻都會很遺憾地無法發揮價值。

講到溝通的隔閡,從開始接網頁相關的案子也滿三年了,持續地成長茁壯後,看到業界發生的大部分情況都是「設計師出稿、工程師刻板」,而且在中間會有很多時候無法溝通,設計師難以了解以程式方式網頁能夠做到的,工程師覺得設計師機車一直在調整小細節或出各種難搞的spec,當固守著自己領域的時候,就會出現像是丟皮球般的埋怨跟被動放棄溝通。

「設計師們,相信我,會了技術的你們根本是外掛,自產素材VI、想動態、實作細節,更可以去探索跟完成原本純視覺設計達不到的事情」

如果有著平面設計的基礎,在設計網站版面的時候,自然能比純工程師有更高的彈性,可以改變跟嘗試的事情就更多了,除了飛來飛去、動來動去的花俏UI之外,一般中規中局的版面規劃也能以平面設計的角度關注細節,自然在介面的規劃上就拉開了一段距離,更別提很多設計師身兼插畫家,可以自己產出網頁用的素材,不用辛苦上google搜尋一堆不同風格的素材之後,苦惱怎麼拼在一起了,這樣的優勢真的是犯規級別。

所以如果設計師學習了網頁程式,有人以設計師的角度去分析,從「想要讓網站視覺變得好的時候要怎麼做」去層層剖析達到目的需要的方法跟教學,就能夠以很短的速度入門、昇華,融合原有的設計既能達到一個新的境界,這樣的境界是新時代的「雜學」,讓工具成為自己的左右手,而非最終的目的。

最後關於價錢的部分,有人跟我說

「2000元你傻啦,這樣的課程去外面xx電腦之類的根本是幾萬塊在收的」

其實我並不怎麼怕,因為你不看課程永遠損失的是自己,學到的東西永遠跟自己的努力成正比的付出。

我在教學中學到的事物,經過講過一遍之後能力三級跳,基礎功更為扎實,其實也算是收穫很多,重點是現在的時代不一樣,群募的線上課程節省了講師用無限重複的時間去授課的缺點,所以這樣開2000元收一千多個學生,跟8000元收二十個學生,而且要不斷地重複一樣的事情,這樣的效果是跟可以帶來的影響力是乘倍數增加的,也是以前時代做不到的,而我也不用那麼大的時間成本重複地授課,可以鑽研自己喜愛的事物。

像是學生裡面就有很多讓我驚嘆的,才剛學會網頁就做出真的很不錯的作品:

大家看完線上課程後創作的一些有趣的作品
大家看完線上課程後創作的一些有趣的作品

他們都是動態網站而不是純平面的作品,靠程式刻出來的! 右上 左上 右下 左下

很主動會去找各種資源/方法w 作品簡歷也簡潔有力(codepen 連結
他的動態超強大的QWQQ 而且超認真(Codepen 連結
有風格在的視覺Guideline(Codepen連結

目前,已經1600人修課 ,超過1/3的人開始第一堂課,將近100人開始完成第一個Project。

如果我們把工具當學科看,只會看到無趣,就像劇本設計一樣,核心思想才是王道,希望所有買跟修這門課的同學,我都能夠幫助到你們,就像在幫助兩年前的自己一樣,不只傳授工具、更傳授了跨領域結合、我所信仰的雜學。

「我們無法一直在這片天空上飛翔,只能奮力保持著盡量不墜落」

一起進化吧,我把到目前為止的能量都放在這邊了, 如果有朝一日能夠讓即使1%的人開始踏出自己的領域,我也滿足了。 現在的各種平台盛行,很難觸及到所有人分享,但願每個進來的人,都能收穫滿滿的離開,展開新的人生道路。 

快瞧瞧哲宇老闆精心製作的線上課程動畫互動網頁程式入門(HTML/CSS/JS)

p.s.如果這門課真的有幫助到你,讓你體會到網頁學習的樂趣, 再請不吝給予評價與分享了:)

看看下一篇:釀造一門結合網頁、設計、數學與特效的線上程式課程

撰文:吳哲宇

墨雨設計banner

這篇文章 從不只是一門線上課程,而是一場推動進化的豪賭 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>
來用可怕的三角函數做網頁吧! -Part 2科幻時鐘(直播筆記) https://creativecoding.in/2021/05/14/%e4%be%86%e7%94%a8%e5%8f%af%e6%80%95%e7%9a%84%e4%b8%89%e8%a7%92%e5%87%bd%e6%95%b8%e5%81%9a%e7%b6%b2%e9%a0%81%e5%90%a7-part2-%e7%a7%91%e5%b9%bb%e6%99%82%e9%90%98/ Fri, 14 May 2021 02:16:00 +0000 https://creativecoding.in/?p=757 上一篇中,老闆利用三角函數幫 DOM 做 CSS 的絕對定位,這次我們雖然也是使用三角函數,但是改使用 canvas 在網頁上繪圖,製作科幻效果的時鐘。

這篇文章 來用可怕的三角函數做網頁吧! -Part 2科幻時鐘(直播筆記) 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>
利用三角函數與 canvas 製作科幻感時鐘
利用三角函數與 canvas 製作科幻感時鐘

本文翻自[週四寫程式系列] 來用可怕的三角函數做網頁吧! – Part2直播影片,對文章內容有疑問,或是想要老闆手把手帶你飛,都可以觀看影片詳細內容。

上次老闆帶大家利用三角函數製作衛星繞月球,還沒自己動手操作的同學,可以回上一篇挑戰,複習三角函數如何結合到網頁中。雖然數學看起來很可怕,但是它卻可以協助你製作有趣的效果,而數學中的表達式在各個地方都通用,不管是製作特效、資料分析,都可以讓你優雅地描述一件事的方式。

這次要製作的科幻效果,使用 FUI 風格,FUI 設計有許多不同的全名 (fake user interface, fictional user interface, fake user interface, 虛構使用者介面),這些 f 開頭的單字,代表還不存在的人機互動介面,常見於科幻電影場景中主角操作的機器介面,或是鋼鐵人 AI 介面…等,透過數據運算組成各種元件,讓畫面看起來科技感十足。

前情提要

開始製作前,老闆這邊提供這次範例的成果網址,讓大家在實作時可以參考。

上一篇中,老闆利用三角函數幫 DOM 做 CSS 的絕對定位,這次我們雖然也是使用三角函數,但是改使用 canvas 在網頁上繪圖。首先,讓我們快速回顧上一篇中提到的,應用三角函數幫 DOM 做絕對定位,讓遊戲元件在正確位置顯示,以砲台射擊遊戲為例,假設右上方有個目標物,我們要讓射出的砲彈的角度一直更新,才能能夠射到目標物,而每段時間砲彈要前進多少距離,則透過三角函數取得每次要調整的距離 Δy, Δx。

<canvas> 是一個 HTML 元素,我們可以利用程式在這個元素上繪圖(通常是用 JavaScript)- MDN

那麼又該如何知道 Δy, Δx 是多少呢?我們知道常見的三角形(30°, 45°, 60°)各邊的比例,但是當不是這些常見的角度時,就束手無策了。這時候我們就要感謝偉大數學家們的努力,只要知道 r 和 θ,就可以將 Δy 與 Δx 用三角函數去換算成 r * sinθ 與 r * cosθ。

數學家也從不同角度的三角形中發現,sinθ 與 cosθ 是一個規律的波浪圖,這代表著 r, Δy 與 Δx 值是成比例的關係。有了這些知識,就能開始著手製作 FUI 風格的時鐘了。以上我們帶大家快速回顧,要看更詳細的三角函數解說,可以參考 Part 1 影片和文章

畫個圓形吧

畫圖前,老闆先帶大家理解畫圓的觀念如下:從三角形、四角形,慢慢到多邊形,當與中心點距離一樣的點數亮夠多,視覺上就會像是畫出一個圓。首先,我們將中心點作為基準,每一次畫出的點與 r 的距離都相同,以 x 軸上的點做為起始點,將一圈 360° 均分為三點時,可以畫出三角形(左圖),四點的時候是四角形(右圖),以此類推,當點的數量夠多的時候就趨近圓形。

該如何將前面的這段敘述用程式寫出來呢?我們可以理解成將 360° 分成特定的份數,在座標軸上右邊 0° 是起始點,逆時針旋轉增加角度,假想有一個固定單位半徑 r 的圓在這個座標軸上,我們要畫出三角形,首先先將 360° 分成三等份,從 0° 的位置先點上一點,逆時針轉 120° 畫一點,最後再逆時針旋轉 120° 畫一點,三個點互相連接後,就成為了三角形,其他多邊形都能用這種方式去畫。聰明的大家這時候就可以發現,如果這個圓上有無限多個點,連接起來之後就趨近圓形。

那麼又該如何算出下圖中點 2 的座標呢?假設今天我們要畫一個 n 邊形,先將圓平分成 n 個點後,每次增加的角度是 360°/n,第 i 個點的角度就是 i *(360° / n)。用前面提到的三角形來做檢驗,第一個點就是 1 * (360° / 3) = 120°,第二個點就是 2 * (360° / 3) = 240°,第三個點就是 3 * (360° / 3) = 360°,也就回到了原點。第二點的座標算法為:x 座標 r * cosθ,y 則是 r * sinθ,其他點的座標算法一樣。接下來,就讓大家跟著老闆開始畫圖吧。

動手做

在我們要開始動手做之前,有幾個重點:

  1. 不能使用 canvas 中畫圓的函數。
  2. 因為電腦無法解讀 ” 從中心畫線到 30° 的位置 ” 這種口語的陳述,所以我們要去換算每個點的 x 與 y 的座標,並將所需要的點連線,才能畫出我們要的圖。

畫圖

理解畫圓的思維邏輯後,先跟大家介紹網頁畫圖的技術,在網頁畫圖我們會使用 canvas 來畫圖,畫圖的方式跟網頁定義 DOM 位置的不同,需要定義每個點的位置,點相連之後畫出我們需要的圖。

開始畫圖前,大家可以先將 codepen 的開發環境以及程式碼設置成跟老闆一樣,避免操作上的出入:

  • html 使用 pug
  • css 使用 sass
  • js 區塊將 jQuery 引用進來

HTML

canvas#myCanvas

CSS(Sass)

html, body
  width: 100vw
  height: 100vh
  margin: 0
  padding: 0
  overflow: hidden
  background-color: #000
canvas
  background-color: #fff

當我們把上面程式碼輸入後,會發現 canvas 的區塊沒有撐滿整個螢幕(下圖白色部分,這邊設定成白色背景是方便大家了解 canvas 的變化,之後在第5步驟開始畫方塊時,會將 canvas 的背景色拿掉)。

該怎麼調整 canvas 畫布跟螢幕一樣呢?我們在 js 區塊中撰寫以下程式碼,步驟如下:

  1. 利用 id 取得畫布的 DOM
  2. 透過取得的 canvas 來取得繪圖元件
  3. 設定畫布的寬高
    我們希望 canvas 可以撐開整個畫面,透過 outerWidth() 以及 outerHeight() 取得視窗的寬高,並將 canvas 畫布的寬高設定成這些值
    JavaScript
// 1. 取得 canvas 畫布
var c = document.getElementById('myCanvas');
// 2. 畫布繪圖,後面開始繪圖才會使用到這個變數
var ctx = c.getContext("2d");

// 3. canvas 畫布設定
var ww = $(window).outerWidth();
var hh = $(window).outerHeight();
// 3. 將螢幕寬高指定給畫布
c.width = ww;
c.height = hh;

4. 更新畫布大小

這時候若是調整螢幕大小,也就是網頁的寬高改變,會發現畫布沒有跟著撐滿版,所以我們必須監聽畫面的 resize,當畫面縮放的時候,動態地抓取當下畫面的寬高並重新設定 canvas 畫布。所以我們將程式碼調整成:

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");

var ww = $(window).outerWidth();
var wh = $(window).outerHeight();

// 將重複使用的程式碼整理成 function
function getWindowSize() {
  ww = $(window).outerWidth();
  wh = $(window).outerHeight();
  c.width = ww;
  c.height = wh;
}

// 進入網頁後先做一次畫布大小調整
getWindowSize();
// 監聽畫面 resize
$(window).resize(getWindowSize);

5. 開始畫圖 – 方塊

要注意在canvas 中畫圖比較特別的是,我們要定義兩點 a 和 b 才能連成線;若是要畫出一個方塊,可以直接透過 canvas 內的 api 拉出方塊後填色,讓我們利用以下幾個語法,畫出位於 (0, 0) 寬度 50px 的正方形:

  • ctx.fillStyle = “white” 填色顏色為白色
  • ctx.beginPath() 開始繪圖
  • ctx.rect(x, y, width, height) 在座標 (x, y) 上畫一個寬 width 高 height 的矩形
  • ctx.fill() 填色
function draw(){
  ctx.fillStyle = "white";
  ctx.beginPath();
  ctx.rect(0, 0, 50, 50);
  ctx.fill();
}

draw();

6. 隨時更新畫布

我們想讓正方形隨著時間往右移動,所以多加了一個時間變數 time,讓 draw function 被呼叫的時候增加 time 的值,並往右移動,所以我們將原本座標 x 跟著時間改變,就產生出一個白色方塊一直向右移動。

var time = 0;
function draw(){
  ctx.fillStyle = "white";
  ctx.beginPath();
  ctx.rect(time, 0, 50, 50);
  ctx.fill();
  time+=1;
}

setInterval(draw, 10);

7. 清空畫布再更新

這時候我們可以發現,方塊是往右了,但是卻變成一條白色的線,那是因為每次畫上新的方塊時,畫布沒有清空。所以我們在每次要畫方塊前,都先畫一個覆蓋整個畫面的長方形,將原本的畫面蓋掉後,再更新正方形。 若是覆蓋的長方形是半透明的會發生什麼事?沒錯!正方形移動時就會產生殘影,大家可以嘗試不同數值試試看。

...
var time = 0;
function draw(){
	ctx.fillStyle = "rgba(0, 0, 0, 0.05)";
  ctx.beginPath();
  ctx.rect(0, 0, ww , wh);
  ctx.fill();

  ctx.fillStyle = "white";
  ctx.beginPath();
  ctx.rect(time, 0, 50, 50);
  ctx.fill();
	time+=1;
}

setInterval(draw, 10);

座標軸基礎設置

透過以上操作,讓大家了解繪圖的基本操作並讓方塊順利移動後,接著準備進入正題。首先我們要先繪製座標軸,但以網頁來說,左上角為坐標(0,0),而這次專案中我們希望座標軸的中心點(0, 0) 改在正中央,所以我們需要將中心點開始移動。

  1. 使用中心點作為初始值

要達成這個目標,我們直覺地想到把方塊移到中心,所以我們多了一組變數來記錄整個螢幕的中心點,並將這個中心點加到白色方塊的初始位置上。這邊還要注意的是,當螢幕 resize 時,center 值也必須更換,總共有以下三個部分的程式碼要調整。

// 多一組變數記錄中心點
var center = {
  x: 0,
  y: 0
};

function getWindowSize() {
  ww = $(window).outerWidth();
  wh = $(window).outerHeight();
  c.width = ww;
  c.height = wh;
  // 重新計算中心點
  center.x = ww/2;
  center.y = wh/2;
}

function draw(){
  ctx.fillStyle = "rgba(0, 0, 0, 0.05)";
  ctx.beginPath();
  ctx.rect(0, 0, ww, wh);
  ctx.fill();
  
  ctx.fillStyle = "white";
  ctx.beginPath();
  // 每次繪製方形的座標時要加上 center 值
  ctx.rect(time + center.x, 0 + center.y, 50, 50);
  ctx.fill();
  time+=1;
}

2. 更改畫布中心

如果我們每次要繪製任何東西時,都要手動加上這個 center 的值,非常地不方便,甚至還有可能遺漏它。所以這時候我們可以使用 canvas 內建的功能,直接改變畫布位置,就不用每次繪製時都要在該元件多加上偏移的座標。這邊我們將 getWindowSize 調整成:

function getWindowSize() {
  ww = $(window).outerWidth();
  wh = $(window).outerHeight();
  c.width = ww;
  c.height = wh;
  
  center.x = ww/2;
  center.y = wh/2;
  
  ctx.restore();
  // 移動畫布座標
  ctx.translate(center.x, center.y);
}

3. 調整 draw()

完成更改畫布中心之後會發現,方塊沒出現在畫面裡,因為我們除了調整中心的畫布之外,也要將方塊的初始值調整回來。大家可以試著調整 draw 中清畫布的顏色,會發現這塊清除的色塊並沒有覆蓋整個版面,也是從中心點往右下長一個方塊,所以這塊清除的畫布的位置也需要調整。

function draw(){
  // 清畫布方塊顏色
  ctx.fillStyle = "rgba(0, 0, 0, 0.05)";
  ctx.beginPath();
  // 調整清除畫布的初始位置
  ctx.rect(-center.x, -center.y, ww , wh);
  ctx.fill();
  
  ctx.fillStyle = "white";
  ctx.beginPath();
  // 白色方塊初始值
  ctx.rect(time, 0, 50, 50);
  ctx.fill();
  time+=1;
}

座標軸

透過白色方塊了解 canvas 繪圖和畫布座標移動後,總算要進入正題。

我們首先先繪製靜態的畫面,第一個就是我們的座標軸,比較不一樣的是,剛剛都是直接畫一個形狀填色,這次要改成用點連出我們需要的線並填色。會用到的程式碼如下:

  • ctx.stokeStyle = ‘rgba(255, 255, 255, 0.05)’ 畫筆顏色
  • ctx.strokeWidth = 1 畫筆粗度
  • ctx.moveTo(x, y) 將畫筆移到 (x, y)
  • ctx.lineTo(x2, y2) 從上一個位置拉一條直線到 (x2, y2)
  • ctx.stroke() 畫圖
function draw(){
  ...
  
  // 座標軸
  ctx.strokeStyle = 'rgba(255, 255, 255, 0.05)';
  ctx.lineWidth = 1;
  ctx.beginPath();
  ctx.moveTo(-ww/2, 0);
  ctx.lineTo(ww/2, 0);
  ctx.moveTo(0, -wh/2);
  ctx.lineTo(0, wh/2);
  ctx.stroke();
  
  ...
}

從方形到圓形

有了座標軸後,我們要在上面畫一個圓形,這邊老闆一樣帶大家從四角形開始理解,了解四角形後,只要畫的點增加到一定數量,繪製出來的多邊形就會趨近於圓形。

我們嘗試畫個半徑為 200 的四邊形,首先第一個點為右邊,要注意的是,網頁的座標跟大家認知上的座標 y 軸方向是相反的,往下是正數,所以第二點是下面,第三個點是左邊,逆時針旋轉,以此類推。

另外要注意的是,網頁中畫圓是用弧度來計算,一圈 360° 等於 2PI,所以我們設一個變數來把角度轉換成弧度,若是沒有用弧度繪圖,就會出現右邊圖裡的窘境。這邊大家也可以試試看,當 n 增加到一定的量,畫出的圖就會趨近於圓形。

function draw(){
  ...
  // 每個點與中心的距離
  var r = 200;
  // 角度轉換成弧度
  var deg_to_pi = Math.PI * 2 / 360 ;
  // 畫 4 個點
  var n = 4;
  ctx.beginPath();
  for(var i = 0; i<=n; i++){
    var deg = i * (360 / n) * deg_to_pi;
    ctx.lineTo(
      r * Math.cos(deg),
      r * Math.sin(deg)
    );
  }
  ctx.stroke();
  ...
}

波浪線

那要怎麼畫旋轉的波浪圓形呢?我們可以觀察到,這個波浪圓形上的每一個點,只是在做半徑的調整,所以我們可以在 r 上面做些手腳,讓它成為一個動態的半徑,就能完成波浪的圓形,至於要如何調整才能讓這個點是在一定的範圍內變動,大家是不是想到 sin 和 cos 的圖了呢?沒錯,只要利用它們和 r 做組合,就可以調整出不一樣的波浪圖。老闆這邊提示大家:

  1. 因為 sin 和 cos 的最大到最小值分別是 1, -1,所以可以多乘上一個數,來增加波浪起伏
  2. 角度變化的越快就會讓波讓越密集,所以在代入 sin 的角度中,也多乘上一個數
  3. 波浪沒有完整的接合起來,是因為沒有把角度完整走完一個圓,一個完整的圓角度是 2PI,只要再多乘上 2PI 運算即可。

大家可以嘗試看看不同數值乘線的效果,那又該怎麼讓波浪圓形動起來呢?這邊我們要在 now_r 變數中的角度部份加入會一直變動的數值,才有辦法讓半徑多加上這個 1 單位到 -1 單位的動態半徑,我們可以觀察到, time 會隨著時間一值增加,只要活用 time 就能讓波浪圓形動起來。

function draw () {
  ...
  // 波浪圓形
  var deg_to_pi = Math.PI / 360 * 2;
  // 基礎半徑值 200
  var r = 200;
  // 200 個點的多邊形
  var n = 200;
  ctx.beginPath();
  for(var i = 0; i<=n; i++){
    // 2 * sin() 增加動態半徑的 range
    // 2 * Math.PI 確保畫出完整的圓
    var now_r = r + 2 * Math.sin(2 * Math.PI *  i / 10 + time / 20);
    var deg = i * (360 / n) * deg_to_pi;
    ctx.lineTo(
      now_r * Math.cos(deg),
      now_r * Math.sin(deg)
    );
  }
  ctx.stroke();
  ...
}

刻度

畫刻度的想法又跟畫圓形不太一樣,兩者都需要使用到角度來輔助畫圖,波浪是每畫一點就改變角度,而畫刻度不一樣的地方在於,是固定角度在 r 畫上一點後,改變 r 的長度後再畫一點連起來,完成一個角度後再到下一個角度用相同方式繪製線。

以下圖為例子,假設我們想畫一個角度 θ ,從半徑 3 連到半徑 5 的線,則先將畫筆移到(3cosθ, 3sinθ),再連線到 ((3+2)*cosθ, (3+2)*sinθ)。用基本的 r 加上某個數值,成為下一個要連線的點,這樣做的好處是,如果今天我們想變成比較長的刻度,只要調整加上的值就可以達成。

我們要畫出的圖需求如下:

  1. 畫一圈半徑為 220 共 240 個刻度所繞出的圓。
  2. 每隔10個刻度,就會有一條中間長度的刻度
  3. 上中下右(也就是每隔 240/4 = 60)有一條最長長度的刻度,

總共有三種樣式的刻度,透過三元運算子,可以先將其中一段拆解出來看,活用三元運算子就能用刻度來組出不同的長度,以下面這個三元運算子解讀的方式如下,當判斷式為 true 時,會執行前者 true 的內容,否則就執行後者 false。

判斷式 ? true : false

所以「當 i 除以 10 的餘數為 0 的時候則會使用 4,否則就使用 0」的三元運算子應該這樣寫:

i % 10 == 0 ? 4 : 0

同樣的,我們也可以將透明度結合三元運算子,在畫線前,賦予畫筆顏色不同透明度。接下來就可以設定兩個點(start_r 到 end_r)與角度,記得角度要乘上前面宣告的 deg_to_pi。

萬事俱備,就能開始繪圖了,一樣使用前面提到的 beginPath(), moveTo(), lineTo(), stroke() 來進行繪製。

var r = 220;
var count = 240;
for(var i=0; i<=count; i++){
  // len 為不同刻度有不同長度的增加量
  var len = 4 + (i % 10 == 0 ? 4 : 0) + (i % 60 == 0? 8 : 0);
  var opacity = (len > 4 ? 1 : 0.5);
  var start_r = r;
  var end_r = start_r + len;
  //最基本的角度分佈
  var deg = 360*(i/count)*deg_to_pi;
  ctx.beginPath();
  ctx.moveTo(
    start_r * Math.cos(deg),
    start_r * Math.sin(deg)
  );
  ctx.lineTo(
    end_r * Math.cos(deg),
    end_r * Math.sin(deg)
  );

  // 決定畫筆樣式
  ctx.lineWidth = 1;
  ctx.strokeStyle = "rgba(255, 255, 255, "+opacity+")";

  ctx.stroke();
}

外圈

外圈的作法很簡單,與剛剛畫內圈的方式雷同,調整 r 以及減少點(count)的數量就可以達成,大家可以按照喜好嘗試調整看看。

function draw () {
  ...
  var r = 400;
  // 共畫 60 個刻度
  var count = 60;
  for (var i = 0; i <= count; i++) {
    // 上中下右刻度要不一樣,等於是每十五個刻度就要不同長
    var len = 4 + (i % 15 == 0 ? 8 : 0);
    var opacity = len > 4 ? 1 : 0.5;
    var start_r = r;
    var end_r = start_r + len;
    var deg = 360 * (i / count) * deg_to_pi;
    ctx.beginPath();
    ctx.moveTo(start_r * Math.cos(deg), start_r * Math.sin(deg));
    ctx.lineTo(end_r * Math.cos(deg), end_r * Math.sin(deg));

    ctx.lineWidth = 1;
    ctx.strokeStyle = "rgba(255, 255, 255, " + opacity + ")";
    ctx.stroke();
  }
  ...
}

秒針、分針、時針

要畫秒針、分真或時針,我們需要知道目前時間,獲得目前時間的方式會用到以下程式,我們也利用 jQuery,將時間放在畫面上,方便我們在製作時能夠參照畫面是否和我們期望的相同。

HTML

canvas#myCanvas
.time +00:00:00

CSS(Sass)

canvas
  transform: scaleY(-1)

JavaScript

var nowTime = new Date();
var sec = nowTime.getSeconds();
var min = nowTime.getMinutes();
var hour = nowTime.getHours();
  
$('.time').text('+00:'+hour+':'+min+':'+sec);

先用固定的角度來測試畫出來的圖形是否跟真實的時鐘一樣,我們傳入 45 作為角度參數後發現一些問題,跟著下面的步驟去微調就能解決:

  1. 將角度多乘上畫圓的角度:畫出來的角度不是 45 度。只要跟前面一樣,將角度轉換成畫圓要用的角度即可。
  2. 從正上方旋轉 45 度:給 45 度為什麼是指向右下呢?我們期望會從正上方作為0度開始旋轉,所以 45 度應該要指著右上方,大家還記得在上一篇有提到,網頁中的座標系 y 軸向下才是正值(左圖),老闆這邊使用偷吃步的方式,只要修改畫布將整張畫布垂直翻轉,45度指的方向就對了。
  3. 讓秒針跟著時間旋轉:緊接著,將角度位置改使用 sec 變數讓秒針動起來。對於秒針而言一圈有 60 個刻度,我們先將 0 到 60 個刻度換算成 0 到 1,再換算 0 到 360,所以就等於 sec / 60 * 360,就是秒針每秒要改變的角度。
  4. 調整旋轉方向:我們可以看到現在以逆時針旋轉,所以我們多乘以一個負值,讓旋轉的方向變成順時針轉的方向。
  5. 補上初始值:最後我們察覺到正確的秒針位置總是少了90度,這就是因為我們現在的座標系初始值 0 度是在右邊,只要將初始值的0換到正上方,這邊我們在函式轉換的角度位置中加上初始值(90度)即可。
function drawPointer(r, deg, lineWidth) {
  // 決定畫筆
  ctx.lineWidth = lineWidth;
  ctx.strokeStyle = "rgba(255, 255, 255, .5)";
	
  // 調整角度初始值與轉化成圓的角度
  var now_deg = (deg + 90) * deg_to_pi;
    
  ctx.beginPath();
  ctx.moveTo(0,0);
  ctx.lineTo(r * Math.cos(now_deg), r * Math.sin(now_deg));

  ctx.stroke();
}

// 秒針分針時針畫法
drawPointer(400, -360 * (sec / 60), 1);
drawPointer(210, -360 * (min / 60), 1);
drawPointer(150, -360 * ((hour + min / 60) / 12 ), 4);

要注意的是,時針畫法比較不一樣,我們會希望時針不是單純指在對應的數字上,還要多加上過了幾分鐘的變化,所以先將過了幾分鐘除以 60,獲得目前經過一小時中的幾分鐘後,再加上小時除以12,因為一圈只有12個刻度,就能獲得目前的度數。

結語

老闆這邊附上這次範例的成果網址,讓大家在實作時可以參考。

這邊讓我們再複習一次整個製作過程:

  1. canvas 網頁繪圖:若是要讓畫布和螢幕同樣大小,要監聽 resize 並重新調整畫布大小。
  2. canvas 動態效果:相當於在畫布上一直重新繪圖,要記得清空畫布後再畫上新東西。
  3. 調整 canvas 座標:canvas 預設左上角為 (0, 0),可以利用 ctx.translate(x, y)調整畫布的位置。
  4. 繪製座標軸。
  5. 從四角形到圓形:利用三角函數來畫出不同形狀,當點的數量足夠時,連起來就會像是圓形,要注意要將角度換算成弧度。
  6. 會動的波浪圓形:在畫圓的時候,透過三角函數來製造波浪,並結合時間就能讓波浪圓動起來。
  7. 繪製刻度:這次範例中的內圈與外圈都是用這種方是去完成,在不同角度上點出兩個點連起來就變成刻度,結合三元運算子就能在不同角度時有不同的樣式。
  8. 繪製秒針、分針與時針:類似刻度的畫法,只是這次第一個點是圓心,再將時分秒換算成角度後畫出第二點並連線。

數學裡面有許多奇怪的東西,但也感謝數學家們的努力,讓我們可以應用在遊戲或動態特效等地方。在第一篇我們用三角函數來幫 DOM 做定位,這一篇則是在 canvas 上繪圖,並適時結合三角函數,產出許多有趣的效果,各位同學挑戰完兩篇三角函數教學之後,可以回頭思考看看兩者的差異,期待大家能利用三角函數做出更多有趣的效果。

工商時間:老闆在 Hahow 有一堂課程 – 動畫網頁特效入門,裡面有一些數學的內容,誘使大家跳坑,一起去學這些恐怖的東西,老闆已經努力將課程講解得有趣點,讓大家在比較沒有壓力的狀況下學習這些數學。(笑

此篇直播筆記由幫手 H 協助整理

墨雨設計banner

訂閱 Creative Coding Taiwan 電子報:

這篇文章 來用可怕的三角函數做網頁吧! -Part 2科幻時鐘(直播筆記) 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>
來用可怕的三角函數做網頁吧! – Part 1 衛星繞月球(直播筆記) https://creativecoding.in/2021/05/10/%e4%be%86%e7%94%a8%e5%8f%af%e6%80%95%e7%9a%84%e4%b8%89%e8%a7%92%e5%87%bd%e6%95%b8%e5%81%9a%e7%b6%b2%e9%a0%81%e5%90%a7-part1-%e8%a1%9b%e6%98%9f%e7%b9%9e%e6%9c%88%e7%90%83/ Mon, 10 May 2021 01:30:00 +0000 https://creativecoding.in/?p=536 在這篇文章中,會先詳細介紹三角函數的計算並轉換為程式語言,再以三角函數的概念,使用 html (pug), css (sass) 與 js ,從零建構出衛星環繞月球的動態網頁效果。 本文翻自[週四寫程…

這篇文章 來用可怕的三角函數做網頁吧! – Part 1 衛星繞月球(直播筆記) 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>
https://imgur.com/iqS8cqe.gif

在這篇文章中,會先詳細介紹三角函數的計算並轉換為程式語言,再以三角函數的概念,使用 html (pug), css (sass) 與 js ,從零建構出衛星環繞月球的動態網頁效果。

本文翻自[週四寫程式系列] 來用可怕的三角函數做網頁吧! – Part 1,若是對文章內容有疑問,都可以觀看影片詳細內容。

前言

這次要跟大家聊聊三角函數,一聽到「三角函數」,肯定會勾起學生時期回憶,『天啊!老師在說什麼???』,我們這次準備了衛星繞月球的案例,將三角函數結合 CSS,實現衛星在圓周上的位置。也讓大家思考,如何在遊戲中使用三角函數?三角函數還能做出什麼變化?

在開始之前,先和大家分享之前經手的兩個案例 Dyverse Studio 與複雜生活節。在 Dyverse Studio (影片 4:29) 專案中,可以看到主頁裡,背景是由很多條線連結起來的,這個效果不可能手寫網頁結構去達成,直接使用圖片旋轉也欠缺真實感。要達成這些計算藝術的效果,三角函數、座標系、canvas 三者是不可或缺的工具。那這些即時繪圖有什麼好處呢?當使用者跟滑鼠互動或是調整一些參數時,網站能夠即時變化去調整顯示出來的效果,跟一般動畫寫死位移或是旋轉相比,多了更多的互動性。附錄中的 codepen 範例網址中,包括會動的海浪波型、 CD 旋轉軌跡等效果,都是利用三角函數製作出來的效果。由於 Dyverse Studio 主頁已改版,這邊提供影片中提到的畫面連結

Dyverse Studio主頁動畫

從遊戲開始出發

開始製作衛星繞地球前,我們要先了解三角函數。在網頁中要搖操控遊戲中的小精靈移動,就會使用 CSS 的 left, top 屬性,要往右走 left 增加,要往上走 top 減少,以此類推,隨著時間增加,移動的位置也跟著改變,就能營造出小精靈在移動的畫面。

這時問題來了,若是今天我們要讓小精靈斜上(右上45°)移動,該怎麼做呢?相信大家一定非常聰明可以想到,只要在同一時間往上和往右移動相同距離就可以了。

問題又來了,如果要改成往右上30°移動呢?右邊的距離跟上面的距離比例分別為1和√3(學生時期數學課的景象慢慢出現在腦海裡…),先不要恐慌這些數字怎麼來的,只要知道要往右上角30°的目標物移動,x 座標每次都加上√3單位,y 每次都往上加上1單位。

若是想要操作物體移動速度的快慢,只要調整每次加上單位的量(10 * 1 和 10 * √3),就能決定綠色球跑得快或慢。但是這樣的換算方式並不夠理想,每次我們要調整速度,就得再去算固定時間往上或往右移動的量。

版本1:知道 x 及 y 的變量,求得角色的下一個位置。

適用於目標位置不改變。

我們可以發現,在30°橫向距離與直向距離的比值不變,都是 1/√3 ( Δy / Δx, Δ, delta 變動值 ),在比值不變的狀態下,我們只要知道 x 或 y 的其中一邊,就能知道另一者。

x+=Δx
y+=Δy

版本2:知道 x 或 y 其中一者,求得角色的下一個位置。

適用於目標位置不改變。

既然我們知道 x 和 y 成比例關係,那我們就能將 y 每次增加的變量換算成Δx * 比例,反之我們也能將 x 每次增加的變量換算成 Δy * 比例。

x+=Δx
y+=(Δx*比例)

以上兩種版本都是在目標物在特定角度下,我們能夠計算出本體抵達目標物的移動方式,但是如果有更多角度的需求時,只有三種角度的比例肯定就不敷使用了。

版本3:知道斜邊 r 之後,r 乘上對應比例,就可以找到 x, y

這時我們就要感謝數學家們的努力,發明了三角函數,只要我們知道本體和目標物的距離 r 與角度 θ,就能利用 sinθ 或 cosθ 知道對應邊的長度了。

那麼 sinθ 的值怎麼來的呢?假設今天有一個座標軸,上面有一個半徑為1單位的圓,我們將不同角度的三角形放進去,讓所有三角形的 r 都剛好等於半徑1單位,就可以求出 sinθ ( r / y ),例如45°的時候,sin45°=1/√2。

有了這些,我們就可以拿本體到目標位置的距離乘上比例( sinθ ) ,來求出 y。同樣地要求出 x,我們就可以改使用 cosθ。但是這個比例的值到底是什麼呢?讓我們來看看第四個版本

版本4:知道 θ ,就能使用 r 結合三角函數作為比例

比例會根據θ而改變

// r = 5
x+=(5*比例)
y+=(5*比例)

// sinθ = y/r
// cosθ = x/r

x += r * cosθ
y += r * sinθ

衛星繞月球

有了這些三角函數的基本概念後,我們來嘗試做衛星繞月球的畫面,但為了強迫自己使用三角函數,我們要限制自己不能使用 css rotate 的屬性,只能利用 top, left (與畫面上方與左方的距離)結合 transform 來達成。

🔔關於 rotate : css 中有個屬性 transform,裡面有許多種值可以選擇,例如: translate, rotate, skew,其中的 rotate 則是以該物件中心為旋轉基準,根據使用者填入的值做旋轉。了解更多

這邊要注意的是,一般來說,旋轉的角度為逆時針,右邊水平線為 0°,順時針旋轉增加角度(圖左),而網頁座標中旋轉的角度與大家的想像不一樣,這邊在衛星旋轉的部分會透過操作詳細敘述。右圖中可以看到,只要知道綠色衛星與月球中心的距離 r 與 θ,就能利用三角函數換算出 y 與 x 座標。

我們這次用 codepen 來製作這個作品,環境調整為 pug 與 sass,會使用到 jq 來快速選擇兩顆衛星。這邊提供大家一個選顏色的工具 colorhunt ,沒有配色靈感時,能夠直接使用別人推薦的色碼。

場景 html 結構

在畫面中分別有星球背後的光暈(.space)、月亮、月亮上的四個坑洞、兩顆衛星,因此我們整個 html 結構可以寫成下面這樣

.space
.moon
  .hole
  .hole
  .hole
  .hole
.yellow
.blue

Sass 重複使用 – @mixin

首先我們先賦予場景基本的屬性,* 的存在是為了讓我們了解每個元件的外框,在完成作品後可以刪除這個 class 內容。

$color_space: ##2c3d4f

*
  border: solid 1px

html, body
  width: 100%
  height: 100%
  padding: 0
  margin: 0
  background-color: $color_space

// 背景光暈
.space
  width: 700px
  height: 700px
  border-radius: 50%
  background-color: lighten($color_space, 10)
  filter: blur(50px)
  position: absolute
  left: 50%
  top: 50%
  // 偏移處理
  transform: translate(-50%, -50%)

.moon
  background-color: #fff
  width: 200px
  height: 200px
  border-radius: 50%

我們可以發現畫面裡的月球、衛星、坑洞,有太多重複需要使用到圓的東西,我們來試試看怎麼將這些屬性整理在一起,讓這些屬性可以不用一直重複撰寫。

我們會發現 .moon 的寬高與圓角是構成圓形的三個屬性,要如何做才能重複使用這些 css 呢? sass 內有個工具叫做 mixin,可以傳入變數進去,在編譯階段就能產出我們需要的 css 內容,這種方式讓我們能減少撰寫重複的程式碼。宣告與使用的方法如下:

@mixin size($w, $h)
  width: $w
  height: $h

@mixin circle($r)
  +size($r, $r)
  border-radius: 50%

.moon
  background-color: #fff
  +circle(50px)

如果想偷懶一下,讓 +size 內只需傳入一個 $r,可以將 @mixin size 中加入判斷式改寫成如下,在 mixin size 中我們可以看到,當有傳入 $h 時, height 就是使用傳入的第二個參數,若是沒有則直接使用 $w 作為 height;寫法2中則是當 $h 參數沒有傳入時,則預設 $h 為 $w

// 寫法1
@mixin size($w, $h:false)
  width: $w	
  @if ($h)
    height: $h
  @else
    height: $w
// 寫法2
@mixin size($w, $h:$w)
  width: $w	
  height: $h

@mixin circle($r)
  +size($r)
  border-radius: 50%

.moon
  background-color: #fff
  +circle(50px)

這時候我們又發現,專案中頻繁地使用到絕對定位並水平垂直置中,理所當然也可以把這些屬性整理成 mixin:

@mixin ab_center
  position: absolute
  left: 50%
  top: 50%
  transform: translate(-50%, -50%)

製作陰影

我們的月球、月球坑洞與衛星都會用到陰影,css 中的 box-shadow 陰影預設是往外長,我們這邊可以多下一個 inset 值,讓陰影變成內陰影,改成 -20px 便是將亮面往左上移動,知道這個方式之後,讓我們試著做做看衛星與月亮坑洞的陰影,可以試著調整陰影顏色或是偏移量。

.moon
  background-color: #fff
  +circle(400px)
  +ab_center
  box-shadow: -20px -20px darken(#fff, 10) inset

月亮不同坑洞

月亮上四個坑洞的 classname 都是 hole ,我們該如何去客製這四個一模一樣的坑洞,讓它們在基本的屬性上再增加不同的位置或是大小?這邊我們使用到 css 的類別選擇器 nth-child,不僅位置可以客製,每個坑洞的大小也可以透過這種方式去調整。

.hole
  &:nth-child(1)
    left: 120px
    top: 130px

不知道大家在分別寫四個坑洞的位置時,有沒有查覺到我們也可以用剛剛的 mixin 去寫呢?同學可以挑戰看看。

@mixin pos($left, $top)
  top: $top
  left: $left

衛星軌道

這一小節中我們要製作衛星軌道,對好位置後,也能夠確認衛星沒有偏離,這邊只要增加 html 結構,並為它們賦予 css 即可,這邊我們只示範 .trace1 的寫法,要特別注意的就是衛星旋轉的圓型軌跡直徑,就是這個軌道寬度和高度:

HTML

.trace1
.trace2

CSS

.trace1
  width: 500px
  height: 500px
  border-radius: 50%
  border: 1px dashed #fff
  +ab_center

旋轉的衛星

幫衛星賦予樣式,在這邊我們想讓衛星有內陰影,以及淺淺的外層黑色光暈。所以我們在 .red 和 .yellow 的 css 上,加上一些程式碼。這邊也可以看到,我們將常用的顏色做成變數,方便之後快速調整,box-shadow 前面的部分是內陰影,逗號後面的則是外層黑色光暈,大家在寫這一段也要記得加上 z-index

這邊提供大家 .red 的 sass 檔,黃色衛星的內容大家可以挑戰看看。

.red
  $color_red: #f24
  background-color: $color_red
  +circle(50px)
  +ab_center
  box-shadow: -10px -10px darken($color_red, 20) inset, 0px 0px 40px rgba(black, 0.3)
  z-index: 100

接著我們要著手撰寫程式碼,讓程式碼動態修改角度,使衛星們順利動起來。

結合前面所解說的方式,利用三角函數來定義旋轉的位置。angle 為旋轉角度,這邊先釐清前面提到的旋轉方向,一般來說水平線右邊為0°,角度增加的方向為逆時針(左圖);但在網頁中 x, y 的方向有所不同,y 向下才是正值,角度增加旋轉的方向為順時針(右圖)。

我們先做一些測試,確定網頁中旋轉的角度是不是如右圖所示。

下面這段程式碼,angle 是我們要觀察的角度變數,r 為紅色衛星的半徑,x 的部份我們有提到要使用三角函數的 cosθ , y 則是使用 sinθ,那為什麼 θ 的值會使用到這麼大串運算式呢?這邊我們先一一理解整段程式碼,javascript 內要使用到 cos 要使用 API – Math.cos(),javascript 內角度不是直接寫數字,要換算成Math.PI,一圈 360° 為 2PI,所以我們將角度除以 360 後乘上 2PI,就能換算成 js 內的角度。

而最後的 – 25 則是偏移量,因為我們在 mixin ab_center 內有寫到translate(-50%, -50%),這邊我們要將這個偏移量修正回來,才不會讓衛星旋轉偏移。

var angle = 0
var r = 250
var x = r * Math.cos((angle/360)*(Math.PI*2))-25
var y = r * Math.sin((angle/360)*(Math.PI*2))-25
$(".red").css("transform", "translate("+x+"px, "+y+"px)")

大家可以慢慢增加 angle 的量,就能發現紅色衛星隨著角度的增加,從右邊水平線順時針轉。

https://imgur.com/p649GNo.gif

接著我們要讓衛星順暢的旋轉,這邊使用到 setInterval。我們先將剛剛的程式碼包裝成 function update,每隔一段時間就增加 time 的量,並更新畫面就能讓角度增加,使用 setInterval 每 30 毫秒呼叫一次,一個順暢的動態就產出了。

若是覺得衛星轉太慢或太快想調整衛星速度,我們只要把 var angle = time 多乘上一個值即可,聰明的大家應該有發現,如果我們乘上的值是負值,就輕鬆的達成反方向旋轉的功能了。

var time = 0
function update(){
  var r = 250
  // var angle = time
  // var angle = time * 0.2
  var angle = time * -0.5
  var x = r * Math.cos((angle/360)*(Math.PI*2))-25
  var y = r * Math.sin((angle/360)*(Math.PI*2))-25
  $(".red").css("transform", "translate("+x+"px, "+y+"px)")
  time+=1
}

setInterval(update, 30)
https://imgur.com/TGkqKLj.gif

這時候問題來了,紅色衛星完成了,黃色衛星的程式碼也類似紅色程式碼,差別只在旋轉半徑、速度、偏移修正不同,那我們要怎麼將它統一呢?這邊我們使用陣列去管理這兩個衛星物件,在 update 內使用 forEach 來修改兩個衛星的位置就可以了。

var time = 0
var stars=[
  {
    el: ".red",
    r: 250,
    speed: -2,
    width: 50
  },
  {
    el: ".yellow",
    r: 340,
    speed: 1,
    width: 70
  }
]

function update(){
  stars.forEach(function(star){
    var r = star.r
    var angle = time * star.speed
    var x = r * Math.cos((angle/360)*(Math.PI*2))-star.width/2
    var y = r * Math.sin((angle/360)*(Math.PI*2))-star.width/2
    $(star.el).css("transform", "translate("+x+"px, "+y+"px)")
  })
  time+=1
}

setInterval(update, 30)
https://imgur.com/iqS8cqe.gif

結語

這邊讓我們再複習一次整個製作過程

  1. 開始製作前,我們先將基本的結構與樣式完成(陰影、坑洞等),過程中我們發現許多重複使用的樣式,例如絕對定位、圓形等,所以我們學到了第一招 sass 中的 mixin。
  2. 我們利用三角函數模擬衛星繞星球旋轉的定位,並確定衛星旋轉的方向後,讓紅色衛星順利轉起來。
  3. 最後我們將旋轉兩個衛星整理成物件,並改寫 update 函式,讓兩顆衛星能共用相同函式旋轉。

數學裡面有許多奇怪的東西,但也感謝數學家們的努力,讓我們可以應用在遊戲或動態特效等地方,即使理解這些數學理論有些頭疼,但是一切都是為了做遊戲和特效。在 part 2 裡我們會再帶大家使用三角函數來製作其他有趣的東西。

下一篇老闆要繼續使用三角函數打造一個科技感的時鐘,讓我們一鼓作氣學習下去吧!

工商時間:老闆在 Hahow 有一堂課程 – 動畫網頁特效入門,裡面有一些數學的內容,誘使大家跳坑,一起去學這些恐怖的東西,老闆會將課程講解得有趣點,讓大家在比較沒有壓力的狀況下學習這些數學。(笑

此篇直播筆記由幫手 H 協助整理

墨雨設計banner

訂閱 Creative Coding Taiwan 電子報:

這篇文章 來用可怕的三角函數做網頁吧! – Part 1 衛星繞月球(直播筆記) 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>
JS及網頁的模板好夥伴:Canvas sketch入門 https://creativecoding.in/2021/04/30/js-canvas-sketch/ Fri, 30 Apr 2021 01:46:00 +0000 https://creativecoding.in/?p=673 哈嚕,我是陳柏文,目前在陽明交通大學人工智慧辦公室擔任全端(主要是前端),語音及影像辨識工程師,因為興趣使然,正努力學習一些新知,所以目前也在墨雨設計擔任小小前端實習生。 Canvas sketch …

這篇文章 JS及網頁的模板好夥伴:Canvas sketch入門 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>
哈嚕,我是陳柏文,目前在陽明交通大學人工智慧辦公室擔任全端(主要是前端),語音及影像辨識工程師,因為興趣使然,正努力學習一些新知,所以目前也在墨雨設計擔任小小前端實習生。

Canvas sketch

今天我要來介紹canvas sketch這個工具,作者是來自英國倫敦的Matt DesLauriers,他是一名creative coding的前端工程師,也是國外知名教學網站FrontendMasters的講師。

為什麼要學習canvas sketch?

許多前端工程師在做creative coding時,往往會不知道該如何起草或者無法統一,在開發上就需要重新造輪子,因為沒有一個統一的模板;而canvas sketch提供了非常好的模板,像是p5, three, webgl, glsl, shader…等,及一些在創作時會時常使用到的便利工具集,你也可以輕鬆使用canvas sketch方便的快捷鍵將創作好的作品輸出成高畫質的png,或著連續輸出多張照片,並運用工具集,創作成gif或mp4…等的檔案,大大提升你創作的便利性及多元性。廢話不多說,先教大家如何用一行程式碼即完成安裝。

Github連結:https://github.com/mattdesl/canvas-sketch

# 將canvas-sketch-cli全域性的安裝,細節的部分可以參考下方github的連結
# https://github.com/mattdesl/canvas-sketch/blob/master/docs/cli.md
npm install canvas-sketch-cli -g

# 接著可以使用以下兩種方式確定是否有安裝成功
canvas-sketch --version # 檢查版本
npm list -g --depth=0 # 檢查npm global安裝了什麼package

安裝完後接著該如何執行呢?

# 運行下方程式碼,即可產生sketch.js的檔案
# 原作者也有提供像是p5.js,webgl,three,glsl...的模板,可供選擇,範例: --template=p5
# Tips: 如果檔案已經存在,可以省略--new
canvas-sketch sketch --new 

下方是產生three的範例,是不是很乾淨俐落呢?

Canvas sketch產生three的範本
Canvas sketch產生three的範本

以Canvas sketch做圖片輸出

在做creative coding時往往前端工程師或是設計師會希望可以將圖片輸出,而canvas-sketch如果點擊畫布並按下 cmd/ctrl+k 便可簡單地將圖片輸出,並可透過程式進行設定(會在下方圖片設定解釋如何使用),或是,如果你習慣使用git,也可以使用 cmd/ctrl+k ,除輸出外,還會將程式碼進行commit,如下圖。

Canvas sketch輸出圖片

如果需要製作gif檔或是mp4檔可以使用 cmd/ctrl+shift+s ,算法為fps*duration,拿我的例子來舉例:4*24 所以總共會輸出96張圖(這邊要注意:如果未設定duration程式會一直輸出,如果不小心遇到,請關掉瀏覽器),接著如果有安裝ffmpeg便可將圖片串接起來,或著使用網路上的工具,這邊我會介紹如何安裝ffmpeg。(如果有使用homebrew也可使用brew安裝,windows請使用choco)

# 安裝ffmpeg
npm install @ffmpeg-installer/ffmpeg --global

# 安裝完成後便可使用--stream 輸出成mp4
canvas-sketch animation.js --output=tmp --stream

# 輸出成gif
canvas-sketch animation.js --output=tmp --stream=gif

# 輸出成gif 但將長寬度改為512
canvas-sketch animation.js --output=tmp --stream [ gif --scale=512:-1 ]
Canvas sketch製作gif檔或是mp4檔
https://imgur.com/RjICB48.gif

圖片輸出的一般設定

下面提供一些輸出的一般設定,如果需要更進階設定選項可以至github上面查詢,此外也可以將圖片透過像是blender, unity的軟體產生更有趣效果唷。

JavaScript

const canvasSketch = require('canvas-sketch');

const settings = {
  dimensions: [ 2048, 2048 ],
  // dimensions: "A4",         // 將圖片輸出成 A4 size
  // orientation: "landscape", // landscape, portrait (背景、人像)
  // units: "cm",              // 預設是px,可更改輸出的單位
  // pixelsPerInch: 300,       // 預設為72,可以輸出更高畫質的圖片 
	// fps: 24                   // 每秒輸出多少張
  // duration: 4               // 輸出長度
  // name: 'foobar',           // 預設為時間time stamp
  // prefix: 'artwork',        // 檔案的前綴
  // suffix: '.draft'          // 輸出檔案檔名
	// encoding: 'image/jpeg',   // 輸出類型
  // encodingQuality: 0.75,    // 輸出壓縮品質
};

const sketch = () => {
  return ({ context, width, height }) => {
    context.fillStyle = 'white';
    context.fillRect(0, 0, width, height);
  };
};

canvasSketch(sketch, settings);

Canvas sketch所提供其他好用的工具

為了方便開發,canvas-sketch的作者也有提供一些好用的工具,像是random,以往我們使用javascript原生的Math.random 每次刷新後都會產生不同的值這裡便可以使用作者製作的random…等的函示。

Github連結:https://github.com/mattdesl/canvas-sketch-util

當然除了作者提供的canvas-sketch-util,還有其他不錯的library像是nice-color-palettes … 等的套件可供使用。

# 安裝canvas-sketch-util
npm install canvas-sketch-util --save

JavaScript

// 隨機數
const random = require("canvas-sketch-util/random");

random.setSeed(1); // 設定後1的值便會存起來
random.value();    // 隨機值
random.gaussian(); // 可以使用類似gussian的函示
random.noise2D();  // 產生兩層的雜質
random.noise3D();  // 產生三層的雜質

// 數學函示
const { fract, lerp } = require('canvas-sketch-util/math');

fract(51.23)       // 扣除整數,得到0.23的值
lerp(0, 50, 0.5)   // 線性插值,0跟50取中間值,所以為25

總結

寫程式寫到現在,在琢磨的過程中,發現前端有很多未知的新東西需要更多的工程師去一起去挖掘及開發,儘管有些難度很高,但越過去後總是能看見另一片天地,而我想這也是每個工程師能一直保持熱忱的主要原因;今天簡單介紹完canvas-sketch這個工具,希望對身為工程師或設計師的你們在開發上能有所幫助,未來如果有新的知識,我也會繼續分享,若是你們有甚麼想知道的,也歡迎透過社群平台告訴我。 ; – )

作者:陳柏文

墨雨設計banner

訂閱 Creative Coding Taiwan 電子報:

這篇文章 JS及網頁的模板好夥伴:Canvas sketch入門 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>
讓我們來快速寫個漂浮感的輪播吧!動態網頁程式教學(直播筆記) https://creativecoding.in/2021/04/26/%e8%ae%93%e6%88%91%e5%80%91%e4%be%86%e5%bf%ab%e9%80%9f%e5%af%ab%e5%80%8b%e6%bc%82%e6%b5%ae%e6%84%9f%e7%9a%84%e8%bc%aa%e6%92%ad%e5%90%a7%ef%bc%81%ef%bc%88%e7%9b%b4%e6%92%ad%e7%ad%86%e8%a8%98%ef%bc%89/ Mon, 26 Apr 2021 05:36:00 +0000 https://creativecoding.in/?p=626 相信大家對於輪播一定不陌生吧,在各大官網、購物網站的重點區域常常可以看到輪播的蹤跡。除了增加與使用者的互動性以外,對於尺寸日漸縮小的行動裝置來說,輪播很重要的一點是可以在有限版面中增加傳遞的資訊量。今…

這篇文章 讓我們來快速寫個漂浮感的輪播吧!動態網頁程式教學(直播筆記) 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>
漂浮感輪播教學成果

相信大家對於輪播一定不陌生吧,在各大官網、購物網站的重點區域常常可以看到輪播的蹤跡。除了增加與使用者的互動性以外,對於尺寸日漸縮小的行動裝置來說,輪播很重要的一點是可以在有限版面中增加傳遞的資訊量。今天我們就來實作如何透過Vue.js簡化座標計算跟更新資料,快速打造漂浮效果的輪播功能吧!

我們將以Code Pen做為本次實作的平台,這是一個可以在創作的同時即時看到程式碼運作狀況的線上程式碼編輯器,只要簡單註冊就可以使用囉!

如果想搭配直播影片一起實作,請往這邊走 👉🏻 https://www.youtube.com/watch?v=GFMnJKy_910

首先在Code Pen上開一個新的pen,將HTML的預處理器設定成Pug、CSS的預處理器設定成Sass、JS的CDN掛入Vue。

輪播中不可缺少的靈魂角色──圖片,這邊介紹一個可供個人也可商用的圖片網站Lorem Picsum(註一),他的特點是圖片是一個個的URL,使用時可直接嵌入網站。除了隨機圖片以外也可以透過/id/{image}指定特定圖片,尺寸大小的部分只要在URL後面加上寬和高就可以囉!另外也有像灰階、模糊等等的參數,可說是練習切版時的必備良藥。

*註一:直播影片中所提的Unsplash it目前已更新成Lorem Picsum,另有一個圖片平台Unsplash提供類似服務,但圖片取得方式為下載。

準備動態網頁的圖片與文案

在JS準備一個陣列works把輪播的材料塞進去,每個輪播分別有標題、敘述和圖片這些素材,在陣列中利用{}區隔。大家可以自由選擇喜歡的圖片跟文案,記得文案跟URL要用雙引號包起來。

套入輪播的材料:標題、敘述和圖片這些素材
套入輪播的材料:標題、敘述和圖片這些素材

接下來用Vue把資料套進來,首先在HTML建立#app,在JS建立一個新的Vue物件,指定Vue的作用範圍為#app並指定data的陣列來源為之前在外定義的works(為了讓Vue能夠使用所以在內部再定義一次)。輪播的原理很像幻燈片,透過指定每一組物件編號、計算他的寬度來達成輪播的效果。既然需要輪流,我們就必須設定起始點為陣列中的第0張now_index:0然後設定每張幻燈片的寬span為930px。

漂浮感輪播教學-設定Vue
設定Vue指定每一組物件編號、計算寬度

動態網頁內幻燈片的輪播是怎麼運作的呢?

把資料都套進來之後接下來要做重複與更新,這邊用以下三個畫面階層來解釋輪播的運作:

  1. Postarea:把元素固定在畫面的中央,有點像是逐格動畫中固定的畫框。
  2. Posts:多個靜態畫面組成的長條畫面。
  3. Postbox:長條畫面中的每一張靜態畫面。

在HTML裡建立上述三個階層的畫面,其中postbox中又包含了cover(圖片)、h1(標題)、h5(敘述)這三個元素。我們直接先用任一張圖片和文案做代表,使用語法v-for迭代陣列中的元素渲染六次模擬效果,之後再把文字和圖片替代進去成變數即可。

使用語法v-for迭代陣列中的元素渲染六次模擬效果,之後再把文字和圖片替代進去成變數即可
#app
  .postarea
    .posts
      .postbox(v-for="index in 6")
        .cover(:style="background-image:url('https://picsum.photos/id/1084/800/600')")
          h1 海象樂園
          h5 趴在冰層上的懶惰動物

有了基礎骨架後來準備拉皮,準備兩組Sass的mixin如下:

  1. flex_center:將物件保持在畫面的垂直水平正中央。
  2. size:快速設定物件的寬和高,考慮到時常會製作正方形的物件,設定成如果沒有額外填寫$h時,自動帶入$w的值。
@mixin flex_center
  display: flex
  justify-content: center
  align-items: center
  
@mixin size($w,$h: $w)
  width: $w
  height: $h

為了不讓畫面隨著播放整個一起移動(scroll),把畫面撐到跟視窗一樣100%大,然後設定overflow:hidden,再把背景設定成深色#1c1c1c。

小心網頁中繼承設定

接下來要設定app、postarea、posts、postbox這四者之間的位置和尺寸,要注意的是CSS觀念中子層如何繼承父層的設定,這樣才會知道在設定這麼多height:100%時到底是吃到誰的高度。先把最外層的#app size撐到100%,然後把現在為div形態的.postbox用語法display:inline-block變成水平(橫向),因為子層寬度大於父層時會自動往下折,所以.postarea需要用語法white-space:nowrap處理,其他寬高設定可以參考以下。

製作幻燈片

先前有說過輪播是透過幻燈片的推移來完成,剛開始我們在Vue有設定過每一張的幻燈片的寬度為930px span:930cover的尺寸為330px,做個小小的數學運算後,可知幻燈片之間的距離應為600px,左右各300px,用語法background-size:cover讓海象完整呈現。

把標題和敘述包在infos中,我們可以觀察到其實文案和圖片只有小部分的重疊,比較偷呷步的做法是把infos包在cover內,用translateX製造偏移。在瀏覽器中h1、h5有預設的margin記得取消,其他參數設定附上詳細的sass給大家參考,這樣單張的幻燈片就做好囉!

sass
.cover
    +size(330px, 100%)
    margin-left: 300px //930px-330px
    margin-right: 300px
    background-size: cover
    +flex_center
    
  .infos
    color: white
    transform: translateX(-200px) //運用X軸偏移製造部份重疊
    text-shadow: 0px 0px 30px rgba(0,0,0,0.3) //避免文案與圖片重疊辨識不清
    *
      margin: 0 //取消預設的h1、h5 margin
    
    h1
      margin-bottom: 10px
      font-size: 50px
      font-weight: 400
      
    h5
      background-color: #fff
      color: #000
      padding: 4px 12px
      font-size: 20px
      font-weight: 300
      box-shadow: 0px 0px 30px rgba(0,0,0,0.3)

準備好幻燈片後,接下來要計算如何播放,在Vue裡面定義一個新的計算屬性computed,內部再包一個會回傳一組CSS動態地套進去的functioncomputed_left。那要如何計算呢?既然.postarea是一個固定的畫框,我們想像.posts這個長條每偏移一次now_index都向左移一個span的寬度,在HTML加上:style ="computed_left",在CSS裡面的.posts加上position: relative才能吃到位置的資訊哦!最剛開始的時候還不用偏移,所以now_index值從0開始。用console.log可以看到偏移的計算結果,記得再return結果。

computed:{
    computed_left(){
      var result={
        "left": (-this.now_index * this.span) + "px"
      };
      console.log(result);
      return result;
    }
  }

動起來了是不是很感動!但你有沒有發現輪播跟已發車的火車一樣一去不回頭,通常我們希望輪播是會循環的,當在最後一張按下下一張的按鈕時,就會自動跳回第一張從頭開始。讓我們稍微思考一下變換的pattern,可以運用餘數和總長度的關係來呈現。

methods: {
    delta(d){
      // 0 1 2 3 4 
      // (-1 + 5) = 4
      // (5 % 5)=0
      // ((id +5) % 5) = 0
      // -1 => ((-1+5) % 5) = 4
      // 1 => ((1+5) % 5) = 1
      // 5 => ((5+5) % 5) = 0
      this.now_index =
        (this.now_index + d +this.works.length) % this.works.length
    }
  }

會循環的輪播才叫輪播

完成了左右切換循環連播的功能,現在來把先前的資料換成變數,原先寫成固定CSS style的cover改寫成Vue的functionbg_css,這樣資料就抽換完成了。

JavaScript

bg_css(url){
      return {
        "background-image": "url("+url+")"
      };
    }

HTML

#app
  .postarea
    .posts(:style="computed_left")
      .postbox(v-for="w in works")
        .cover(:style="bg_css(w.cover)")
          .infos
            h1 {{w.title}}
            h5 {{w.description}}

再加上互動按鈕

有了輪播的圖片,少不了左右切換的按鈕和使用者互動,把font-awesome(一個提供很多icon的免費平台)掛入CSS的CDN。

在font-awesome上選好左右icon後加在HTML內,在CSS設定按鈕的參數。

這邊大家可以根據自己的美感調整,通常在執行動作時都會加上transition讓互動不會那麼生硬,這時可以新增transition的mixin來統一整個網站的互動參數。

@mixin trans($t:0.5s, $td:0s)
  transition: $t $td
//t為變化持續的時間,td為延遲變化的時間

在HTML裡再用click把剛剛寫的function delta綁定在按鈕上,往左往右分別設定成1和-1,可用按鈕操作的輪播就大功告成啦!

最後起鍋前再加點鹽 最後再加一些微互動提升質感,通常互動可以以滑鼠事件為主,當使用者的滑鼠進入到特定區塊時,透過放大或偏移來增加點擊的機率。這邊提供老闆的做法讓大家參考,也可以想想還有什麼其他有趣的互動唷!

SASS

.cover
    +size(330px, 100%)
    margin-left: 300px //930px-330px
    margin-right: 300px
    background-size: cover
    background-position: center center
    +flex_center
    +trans
    cursor: pointer
    
    &:hover
      +size(340px,110%)
      .infos
        transform: translateX(-220px) translateY(-10px)

另外我們也可以透過Vue,在物件符合特定條件下時,才加入指定的動畫。這邊呈現的效果是當幻燈片切入的瞬間,從淺到深的透明度轉換效果。

HTML

當現在呈現的物件的id=now_index時,就會帶入cur_item的效果

.postbox(v-for="(w,id) in works", :class="{cur_item: id==now_index}")

CSS

針對cover設定一組名為fadeIn的keyframe,切換的瞬間會從透明度0變成透明度1,x軸也會稍微偏移,整組動畫的時間為1秒,動態為ease。infos也加上一些x軸偏移的效果增加速度感。

@keyframes fadeIn
  0%
    opacity: 0
    transform: translateX(30px) 
    filter: saturate(0%)
  100% 
    opacity: 1
    transform: translateX(0px) 
    filter: saturate(100%) 
 
@keyframes sliceIn
  0%
    transform: translateX(-50px) 
  100%
    transform: translateX(0px) 

.cur_item
  .cover
    animation: fadeIn 1s ease both
  .infos
    h5
      animation: sliceIn 1s 0.1s ease
```

以上就是這次如何用Vue.js快速做出輪播效果,從最一開始的資料處理、計算輪播距離和計算delta變化量轉換成座標,最後再加上一些玩轉的細節動畫。

希望大家還喜歡這次的小範例,如果對類似的網頁效果有興趣,歡迎來看看我們在Hahow所開設的動畫互動網頁程式入門(HTML/CSS/JS)以及動畫互動網頁特效入門(JS/CANVAS)有更多好玩的網頁動畫教學,那我們下次再見囉。

Codepen實作範例:https://codepen.io/frank890417/pen/bWrKOZ

此篇直播筆記由幫手 Jeudi Kuo 協助整理

墨雨設計banner

訂閱 Creative Coding Taiwan 電子報:

這篇文章 讓我們來快速寫個漂浮感的輪播吧!動態網頁程式教學(直播筆記) 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>
老闆的網頁實驗室 #1 — 實作CSS拆字動畫 https://creativecoding.in/2020/03/06/%e8%80%81%e9%97%86%e7%9a%84%e7%b6%b2%e9%a0%81%e5%af%a6%e9%a9%97%e5%ae%a4-1-%e5%af%a6%e4%bd%9ccss%e6%8b%86%e5%ad%97%e5%8b%95%e7%95%ab/ Thu, 05 Mar 2020 17:27:19 +0000 https://creativecoding.monoame.com/?p=79 案例解析 https://rogue.studio/ 這次的老闆網頁實驗室,要來分析一個國外的工作室網站,在這個網站中,有標題一個一個字跑入的效果,這樣的效果怎麼達到的呢?其實這樣的效果並不複雜,程式…

這篇文章 老闆的網頁實驗室 #1 — 實作CSS拆字動畫 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>
案例解析

https://rogue.studio/

這次的老闆網頁實驗室,要來分析一個國外的工作室網站,在這個網站中,有標題一個一個字跑入的效果,這樣的效果怎麼達到的呢?其實這樣的效果並不複雜,程式上也不會特別難達到,老闆特別喜歡他遮罩切入的感覺,要怎麼樣重現這個標題動畫套到網頁上呢?

https://rogue.studio/
https://rogue.studio/

在分析這個案例的時候很有趣的點是,如果一個一個自己手動去指定字最後擺放的位置會很麻煩,所以我們應該盡可能的利用 html 本身layout的功能,讓每個字母產生在我們希望他正常排列在文字裡面的位置之後,再把他拆成不同的元素做動畫。


第一個步驟 — 將文字拆成兩層span

首先,我們第一個目標是將整段文字,拆成分別的元素,才能去控制動畫。

內外框的拆字
內外框的拆字

在看原本的網頁時,你會發現切進來的效果彷彿原本字母的框框位置並沒有移動,超出框框的部分被切掉,所以在這種情況下,應該要分成內外兩個框框,外部的框框負責才切多出來的部分,內部的利用tranform移動,在不影響排版的情況下移動到框框裡面來。

我們希望html中內容可以越簡單越好,不用去管動畫,只要加上一個class — slideLetterIn,動畫就會自動處理跟套上去。

<h1 class=”slideLetterIn”> MONOAME STUDIO </h1>

在抓到所有有slideLetterIn的class後,我們可以利用span標籤,與inline-block屬性,把原本在同一個元素裡面的字母拆成一個一個的span,再整包放會去,讓他們當下仍參與整個字母的排列,所以乍看之下會跟還沒有拆開之前相同,但實際上已經變成內外兩層的方塊文字了!

這邊用到的是js的陣列操作方法 -map轉換跟join結合,中間的過程使用split(“”)把字串拆成一個一個文字,放入雙層的span,join成新的整坨html之後放回原本的元素裡面去。

var titleEls = document.querySelectorAll(".slideLetterIn")
titleEls.forEach(el=>{
  el.innerHTML = el.innerText
    .split("")
    .map(l=> `<span class='outer'>
                <span class='inner'>${l}</span>
              </span>`)
    .join("")
})

第二個步驟 — 製作 CSS 動畫跟控制

接下來,我們要製作一個組keyframe動畫,讓他套在每個字母上,並讓他們之間有時間差。

我們在看動畫控制的時候,可以先找出重複動作的部分,每個字母切進來的轉的角度跟移動相同,但是一個一個字會循序漸進進來。對於每一個字母我們可以套用相同的動畫,透過display: inline-block 讓他參與排列在同一行,同時有block屬性做transform。

.slideLetterIn 
  .outer
    overflow: hidden
    display: inline-block
  .inner
    display: inline-block
    transform: translate(70%) rotate(30deg)
  &.active /* 當字母進來時加上這個class */
    inner
      transform: translateX(0px)

然後字母根據他們是在整段文字裡面的第幾個元素來指定delay的時間,用scss(或sass)程式化的方式產生 nth-child(i),依序指定他們的transition-delay即可。

.slideLetterIn 
  span
    //使用loop指定第1-100個元素每個都會慢0.05秒開始動畫
    @for $i from 1 through 100
      &:nth-child(#{$i}) .inner
        transition-delay: #{$i*0.05s}
進出的delay效果

速度控制曲線參考: https://easings.net/#easeInOutSine

靈活的應用速度曲線,能比用預設的緩進緩出(ease-in-out) 帶來更生動的感覺,這次使用的easeOutQuint,是用四次方倍的動畫速度播放,因此動作開始時會比較快,創造俐落但是有彈性的感受,使用上只要把cubic-bezier指定進來到css的transition屬性即可。

速度曲線

第三個步驟 — 製作景深hover

第三個步驟是最後的點綴,網頁上滑鼠滑到字母上的時候,會有種往後移動失焦的感覺,滑鼠離開後慢慢的回復,在原始的網站中,一個字母變糊後會影響到周圍的幾個字也跟著糊,這邊製作簡易版的滑鼠上去會讓字糊化,離開時會需要一段時間恢復狀態製造連續的感覺。

Hover時模糊

直接套用預設的動畫速度看起來會很死板,因此我這邊技巧上讓他hover前後的變換時間不同,一但滑鼠移動到上面開始動畫後,就改變成快速進入的速度曲線到達最糊的狀態,滑鼠移出時,則是套用原本的緩入曲線,讓他慢慢回覆到原始的狀態,quadIn緩出的動畫速度套上去,然後變回來時再使用緩進的動畫速度。

span
  &.outer
    transition: 1s cubic-bezier(0.55, 0.055, 0.675, 0.19) //進出有不同的速度曲線
    cursor: pointer
    &:hover
      filter: blur(5px)
      transition: 0.5s cubic-bezier(0.165, 0.84, 0.44, 1) //進出有不同的速度曲線
      opacity: 0.9
      transform: scale(0.97)

測試控制的部分我,我們加上一個checkbox,讓他改變時會去toggle最外層的class,加上了active是文字進入,會把單獨文字的transform設為0,文字就會進來,移除active就會套用原本文字的旋轉跟位移,讓文字跑出框框。

<div class="control">
  <label>Toggle
    <input id="toggle" type="checkbox" onchange="toggle()"/>
  </label>
</div>
function toggle(){
  document.querySelector(".slideLetterIn").classList.toggle("active")
}
setTimeout(function(){ 
  toggle()
},1000)

登愣,老闆上菜啦!

最後做出來的效果是這樣:

See the Pen SliceInTexts by Majer @Monoame Design (@frank890417) on CodePen.

其實這個範例的效果也可以用其他方式達到,比如canvas或是WebGL,就能夠達成更酷的像是文字扭曲、粒子特效、色散的效果。

如果大家有興趣看更多類似的分享的話,留言回覆你想要看什麼網站的拆解,老闆會帶著雞尾酒跟檸檬來拆解各式各樣有趣的網站,這篇如果超過15個留言的話,就來教大家怎麼去做區塊的模糊效果,以及能用哪些其他的方式去玩速度曲線,變化應用在不同的使用情境!

參考資料:

課程推薦

老闆在Hahow好學校開了兩門課,其中,動畫互動網頁程式入門(HTML/CSS/JS)以簡單例子帶你入門網站的基礎架構及開發,用素材刻出簡單有趣又美觀的網頁和動畫,享受做出獨一無二的網頁所帶來的成就感,在職場上與設計師和工程師合作無間。

打好基本的互動網頁基礎之後,可以進階動畫互動網頁特效入門(JS/CANVAS),紮實掌握JavaScript 程式與動畫基礎以及進階互動,整合應用掌控資料與顯示的Vue.js前端框架,完成具有設計感的互動網站。期待在課程裡見到你!

墨雨設計banner

訂閱 Creative Coding Taiwan 電子報:

這篇文章 老闆的網頁實驗室 #1 — 實作CSS拆字動畫 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>