Just Do It - 開啟canvas之旅

致懂得努力的我們

夫君子之行,靜以修身研叫,儉以養(yǎng)德锤窑。非淡泊無以明志,非寧靜無以致遠(yuǎn)嚷炉。夫?qū)W須靜也渊啰,才須學(xué)也,非學(xué)無以廣才申屹,非志無以成學(xué)绘证。

淫慢則不能勵精,險躁則不能治性独柑。年與時馳迈窟,意與日去,遂成枯落忌栅,多不接世车酣,悲守窮廬,將復(fù)何及索绪!

2018.12.12晚上 帶大家一起實現(xiàn)你畫我猜的畫板

畫板

主要內(nèi)容

  • Canvas api講解
  • 繪畫
  • 橡皮擦
  • 圖片生成
  • 本地保存
  • 畫筆切換

公開課時間:
12月12日 晚上 20:00~21:30

在線地址:
https://ke.qq.com/course/58689

教室地址:
北京昌平區(qū)回龍觀東大街地鐵A口出湖员,向西走100米(緊鄰?fù)侍茫┒?01教室

Canvas簡述

Canvas 是HTML5新增的元素,讓我們通過JavaScript腳本來繪制圖像, 可以用JavaScript在上面繪制各種圖表瑞驱、動畫等娘摔。

基于Canvas的一些庫:

Canvas基本用法

創(chuàng)建一個畫布

<canvas id="canvas" width="300" height="300">
  <p>你的瀏覽器不支持Canvas</p>
</canvas>

如果你的瀏覽器不支持canvas標(biāo)簽,則標(biāo)簽內(nèi)的文字會被顯示出來

canvas跟img元素很相像唤反,唯一不同的是它沒有src和alt屬性凳寺,canvas標(biāo)簽(除了選擇器)只有width和height兩個屬性鸭津,canvas 如果不設(shè)置寬高,默認(rèn) 300*150肠缨。

獲取渲染上下文

var canvas = document.querySelector('#canvas')

// 獲取2D畫布的渲染上下文
var ctx = canvas.getContext('2d')

context.getContext() 獲取渲染上下文逆趋,該對象提供了用于在畫布上繪圖的方法和屬性

提示:在未來,如果 canvas 標(biāo)簽擴展到支持 3D 繪圖晒奕,getContext() 方法可能允許傳遞一個 "3d" 字符串參數(shù)闻书。

console.log(ctx) // 2D渲染上下文對象
image

從畫一條直線開始

JS

// 通過canvas元素設(shè)置寬高
canvas.width = 400
canvas.height = 400

// 設(shè)置線條寬度
ctx.lineWidth = 10

// 設(shè)置畫筆開始繪制坐標(biāo)(落筆點)
ctx.moveTo(100, 100)
// 連接點
ctx.lineTo(300, 300)

// 設(shè)置繪制顏色
ctx.strokeStyle = 'red'
// 根據(jù)moveTo和lineTo定制的路徑 進行繪制
ctx.stroke()

頁面效果

image

繪制路徑

canvas繪圖是基于路徑的,肉眼看不到脑慧,先進行路徑繪制 然后再通過 fill(填充)或 stroke(描邊)等方法進行填充或繪制魄眉。

涉及api講解

  • lineWidth
    設(shè)置當(dāng)前繪制線條的寬度。默認(rèn)值:1像素

  • moveTo(x, y)
    相當(dāng)于畫筆落筆點 開始一條路徑 相對于畫布左上角 x軸坐標(biāo) y軸坐標(biāo)

  • lineTo(x, y)
    指定連接點坐標(biāo)闷袒,自動和上一個坐標(biāo)點進行連接 繪制路徑 相對于畫布左上角 x軸坐標(biāo) y軸坐標(biāo)

  • strokeStyle
    設(shè)置通過stroke 繪制描邊的顏色坑律。默認(rèn)值:#000

  • stroke
    根據(jù)moveTo和lineTo定制的路徑 進行繪制描邊

繪制幾何圖形

繪制三角形

HTML

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

JS

var canvas = document.querySelector('#canvas')
var ctx = canvas.getContext('2d')

// 設(shè)置繪制線條寬度
ctx.lineWidth = 10
// 設(shè)置繪制線條顏色
ctx.strokeStyle = 'red'
// 設(shè)置填充顏色
ctx.fillStyle = 'pink'

// 開始一條全新的繪制路徑
ctx.beginPath()

// 制定路徑
ctx.moveTo(300, 50)
ctx.lineTo(550, 500)
ctx.lineTo(50, 500)

// 閉合路徑
ctx.closePath()
// 進行填充
ctx.fill()
// 進行繪制
ctx.stroke()

頁面效果

image

涉及api講解

  • fillStyle
    設(shè)置填充色 默認(rèn)值:#000

  • fill
    根據(jù)fillStyle 對當(dāng)前路徑進行填充

  • beginPath
    開始一條全新的繪制路徑

  • closePath
    閉合當(dāng)前路徑,創(chuàng)建從當(dāng)前點到開始點的路徑

路徑相關(guān)方法講解

1.beginPath
開始一個全新繪制的路徑

假如我要繪制兩條顏色不同的平行線條

HTML

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

JS

var canvas = document.querySelector('#canvas')
var ctx = canvas.getContext('2d')

ctx.moveTo(100, 100)
ctx.lineTo(500, 100)
ctx.strokeStyle = 'yellow'
ctx.stroke()

ctx.moveTo(100, 200)
ctx.lineTo(500, 200)
ctx.strokeStyle = 'red'
ctx.stroke()

ctx.moveTo(100, 300)
ctx.lineTo(500, 300)
ctx.strokeStyle = 'blue'
ctx.stroke()

不加beginPath情況下囊骤,后面stroke 會從最初路徑開始坐標(biāo)重新繪制一遍 導(dǎo)致之前路徑描邊顏色發(fā)生疊加

image

在每一次moveTo之前 加上beginPath方法 開始一個全新路徑

JS

// 通常習(xí)慣在第一次的時候也加上beginPath 讓代碼看上去一致
ctx.beginPath()
ctx.moveTo(100, 100)
ctx.lineTo(500, 100)
ctx.strokeStyle = 'yellow'
ctx.stroke()

ctx.beginPath()
ctx.moveTo(100, 200)
ctx.lineTo(500, 200)
ctx.strokeStyle = 'red'
ctx.stroke()

ctx.beginPath()
ctx.moveTo(100, 300)
ctx.lineTo(500, 300)
ctx.strokeStyle = 'blue'
ctx.stroke()

添加beginPath后

效果如下:

image

2.closePath

假如我們繪制一個幾何圖形如上脾歇,closePath會創(chuàng)建從當(dāng)前結(jié)束點到開始點的路徑 形成閉合路徑

JS

ctx.lineWidth = 10
ctx.strokeStyle = 'red'
ctx.fillStyle = 'pink'

ctx.beginPath()

ctx.moveTo(300, 50)
ctx.lineTo(550, 500)
ctx.lineTo(50, 500)

ctx.fill()
ctx.stroke()

不加closePath時 是這樣

image

添加上closePath

JS

ctx.lineWidth = 10
ctx.strokeStyle = 'red'
ctx.fillStyle = 'pink'

ctx.beginPath()

ctx.moveTo(300, 50)
ctx.lineTo(550, 500)
ctx.lineTo(50, 500)

// 閉合路徑
ctx.closePath()

ctx.fill()
ctx.stroke()

添加closePath

效果如下:

image

closePath例子:

JS

ctx.lineWidth = 10
ctx.strokeStyle = 'red'

ctx.beginPath()
ctx.moveTo(300, 100)
ctx.lineTo(500, 500)

ctx.lineTo(300, 500)
ctx.closePath()

ctx.lineTo(100, 500)
ctx.stroke()

效果如下:

image

繪制矩形

rect(x, y, width, height)

創(chuàng)建一個矩形,需要通過stroke() 進行繪制

JS

var canvas = document.querySelector('canvas')
var ctx = canvas.getContext('2d')

ctx.strokeStyle = 'red'
ctx.beginPath()
ctx.rect(100, 100, 300, 300)
ctx.stroke()

效果如下:

image

strokeRect(x, y, width, height)

根據(jù)strokeStyle指定顏色進行矩形描邊淘捡,繪制無填充色的矩形。
同 rect+stroke 一樣效果

JS

var canvas = document.querySelector('canvas')
var ctx = canvas.getContext('2d')

ctx.beginPath()
ctx.lineWidth = 10
ctx.strokeStyle = 'red'
ctx.rect(100, 100, 300, 300)
ctx.stroke()

效果如下:

無填充矩形

fillRect(x, y, width, height)

繪制具有填充色的矩形

JS

var canvas = document.querySelector('#canvas')
var ctx = canvas.getContext('2d')

ctx.beginPath()
ctx.fillStyle = 'blue'
ctx.fillRect(100, 100, 300, 300)

效果如下:

填充矩形

完整繪制一個矩形

JS

var canvas = document.querySelector('#canvas')
var ctx = canvas.getContext('2d')

ctx.lineWidth = 10
ctx.fillStyle = 'blue'
ctx.strokeStyle = 'red'

// 方式一
ctx.fillRect(100, 100, 200, 200)
ctx.strokeRect(100, 100, 200, 200)

// 方式二
ctx.rect(320, 100, 200, 200)
ctx.fill()
ctx.stroke()
矩形

繪制帶陰影矩形

JS

var canvas = document.querySelector('#canvas')
var ctx = canvas.getContext('2d')

// 陰影模糊度
ctx.shadowBlur = 20
// 陰影顏色
ctx.shadowColor = 'black'

// 繪制帶藍(lán)色填充色的矩形
ctx.fillStyle = 'blue'
ctx.fillRect(100, 100, 200, 200)
陰影矩形

線條相關(guān)屬性

lineCap

設(shè)置線條兩端線帽的樣式 context.lineCap=“butt|round|square”;

lineCap屬性值

注意:"round" 和 "square" 值會使線條略微變長池摧。

JS

var canvas = document.querySelector('#canvas')
var ctx = canvas.getContext('2d')

ctx.lineWidth = 20
ctx.beginPath()
ctx.moveTo(100, 100)
ctx.lineTo(500, 100)
// 默認(rèn)值
ctx.lineCap = 'butt'
ctx.stroke()

ctx.beginPath()
ctx.moveTo(100, 200)
ctx.lineTo(500, 200)
// 兩末端圓形線帽
ctx.lineCap = 'round'
ctx.stroke()

ctx.beginPath()
ctx.moveTo(100, 300)
ctx.lineTo(500, 300)
// 兩末端方形線帽
ctx.lineCap = 'square'
ctx.stroke()

效果如下:

lineCap屬性

繪制圓形

arc

JavaScript 語法:

context.arc(x,y,r,sAngle,eAngle,counterclockwise);

參數(shù)

image

JS

var canvas = document.querySelector('#canvas')
var ctx = canvas.getContext('2d')

ctx.lineWidth = 10
ctx.beginPath()

ctx.arc(300, 300, 100, 0, Math.PI * 2, false)

ctx.strokeStyle = 'blue'
ctx.fillStyle = 'red'
ctx.fill()
ctx.stroke()

效果如下:

image

開始角與結(jié)束角:

image

繪制半圓

JS

var canvas = document.querySelector('#canvas')
var ctx = canvas.getContext('2d')

ctx.lineWidth = 10
ctx.beginPath()

// 逆時針繪制
ctx.arc(300, 300, 100, 0.5 * Math.PI, 1.5 * Math.PI, true)

ctx.strokeStyle = 'green'
ctx.fillStyle = 'red'
ctx.fill()
ctx.stroke()

效果如下:

半圓

繪制五角星

JS

var canvas = document.querySelector('#canvas')
var ctx = canvas.getContext('2d')


// 計算x軸坐標(biāo)值
// X = Math.cos(弧度) * 半徑 + 圓心x軸坐標(biāo)
var cx = function(i, r, x, d) {
  return Math.cos((d + i * 72) / 180 * Math.PI) * r + x
}

// 計算y軸坐標(biāo)值
// Y = Math.sin(弧度) * 半徑 + 圓心y軸坐標(biāo)
var sy = function (i, r, y, d) {
  return -Math.sin((d + i * 72) / 180 * Math.PI) * r + y
}

/**
 * @desc 繪制五角星
 * @param  {Object} ctx  2d渲染上下文
 * @param  {Number} r  內(nèi)圓半徑
 * @param  {Number} R  外圓半徑
 * @param  {Number} x  圓心x軸位置
 * @param  {Number} y  圓心y軸位置
 * @param  {Color} fillColor  填充色
 * @param  {Color} strokeColor  描邊色
 *
 */
function drawStart(ctx, r, R, x, y, fillColor, strokeColor) {
  ctx.fillStyle = fillColor
  ctx.strokeStyle = strokeColor

  ctx.beginPath()
  // 繪制五個角
  for (var i = 0; i < 5; i++) {
    // 繪制外圓路徑
    ctx.lineTo( cx(i, R, x, 18), sy(i, R, y, 18))
    // 繪制內(nèi)圓路徑
    ctx.lineTo( cx(i, r, x, 54), sy(i, r, y, 54))
  }
  ctx.closePath()
  ctx.fill()
  ctx.stroke()
}
drawStart(ctx, 100, 200, 300, 300, 'red', 'white')

效果如下:

五角星

五角星數(shù)學(xué)知識補下

image
// 求弧度
// 為L = n(圓心角度數(shù))× π × r(半徑)/180(角度制)

// 對邊與斜邊的比叫做正弦(sine)焦除,記作sin
// 鄰邊與斜邊的比叫做余弦(cosine),記作cos
// 對邊與鄰邊的比叫做正切(tangent)作彤,記作tan

// JS Math.sin() 與 Math.cos() 用法
// Math.sin(x) x 的正玄值膘魄。返回值在 -1.0 到 1.0 之間
// Math.cos(x) x 的余弦值。返回的是 -1.0 到 1.0 之間的數(shù)
// 這兩個函數(shù)中的X 都是指的“弧度”而非“角度”竭讳,

// 弧度的計算公式為:2 * PI / 360 * 角度
// 30° 角度 的弧度 = 2 * PI / 360 * 30

// 如何得到圓上每個點的坐標(biāo)创葡?
// 在圓的坐標(biāo)系中 半徑r為斜邊 x軸為鄰邊 y軸為對邊
// 正弦 = y / r
// 余弦 = x / r

// 解決思路:根據(jù)三角形的正弦、余弦來得值
// 假設(shè)一個圓的圓心坐標(biāo)是(a, b)绢慢,半徑為r

// X = 圓心x軸坐標(biāo) + 弧度的余弦值 * 半徑
// 則圓上每個點的X坐標(biāo)= a + Math.cos(2 * Math.PI / 360) * r

// Y = 圓心y軸坐標(biāo) + 弧度的正弦值 * 半徑
// Y坐標(biāo) = b + Math.cos(2 * Math.PI / 360) * r

// 計算x軸坐標(biāo)值
// X = Math.cos(弧度) * 半徑 + 圓心x軸坐標(biāo)
var cx = function(i, r, x, d) {
  return Math.cos((d + i * 72) / 180 * Math.PI) * r + x
}

// 計算y軸坐標(biāo)值
// Y = Math.sin(弧度) * 半徑 + 圓心y軸坐標(biāo)
var sy = function (i, r, y, d) {
  return -Math.sin((d + i * 72) / 180 * Math.PI) * r + y
}

ctx.lineTo(X, Y)
image

該文章配套源碼地址

https://github.com/Lwenli1224/canvas_base

獲取更多學(xué)習(xí)資源

珠峰微信號

珠峰公眾號
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末灿渴,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子胰舆,更是在濱河造成了極大的恐慌骚露,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缚窿,死亡現(xiàn)場離奇詭異棘幸,居然都是意外死亡,警方通過查閱死者的電腦和手機倦零,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門误续,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吨悍,“玉大人,你說我怎么就攤上這事蹋嵌∮希” “怎么了?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵欣尼,是天一觀的道長爆雹。 經(jīng)常有香客問我,道長愕鼓,這世上最難降的妖魔是什么钙态? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮菇晃,結(jié)果婚禮上册倒,老公的妹妹穿的比我還像新娘。我一直安慰自己磺送,他們只是感情好驻子,可當(dāng)我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著估灿,像睡著了一般崇呵。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天,我揣著相機與錄音冲九,去河邊找鬼。 笑死犹褒,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的弛针。 我是一名探鬼主播叠骑,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼削茁!你這毒婦竟也來了宙枷?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤茧跋,失蹤者是張志新(化名)和其女友劉穎朦拖,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體厌衔,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡璧帝,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了富寿。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片睬隶。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡锣夹,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出苏潜,到底是詐尸還是另有隱情银萍,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布恤左,位于F島的核電站贴唇,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏飞袋。R本人自食惡果不足惜戳气,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望巧鸭。 院中可真熱鬧瓶您,春花似錦、人聲如沸纲仍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽郑叠。三九已至夜赵,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間乡革,已是汗流浹背油吭。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留署拟,地道東北人。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓歌豺,卻偏偏與公主長得像推穷,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子类咧,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,925評論 2 344