前面我们学了js基础知识,只能停留在基本使用阶段,必须实战才能更好的掌握,本文涉及的知识点如果有不会的可以参考三万字js基础总结 或者 看到不会的api可以搜关键词 + mdn
- 需求1: es6面向对象的方式实现一个七巧板
- 需求2: 颜色可以随机改变而不是写死
- 需求3: 颜色可以随机改变的同时且不重复
canvas基础知识点介绍
Canvas Api:提供js和HTML的<canvas>元素来绘制图形的方式,可以用于动画、游戏画面、数据可视化、图片编辑以及实时视频处理等方面
如何创建?
可以通过js方式 或者通过HTML的canvas标签来创建
- js方式
let canvas = document.createElement('canvas')
let ctx = canvas.getContext('2d')
- HTML方式
<canvas id="canvas"
width="1024"
height="1024"
style="border:1px solid #aaa;
display:block;margin:0 auto"
>
浏览器不支持canvas 标签内部判断是否支持 不支持就会显示这段文字
支持的化不会显示这里面的文字
</canvas>
canvas对象上的属性和方法
- canvas.width
- canvas.height
- canvas.getContext('2d')
canvas画一条线
画线: 起点是哪里,然后连线,最后填充
let ctx = document.createElement('canvas').getContext('2d')
//draw a line
ctx.moveTo(0,0)//左上角
ctx.lineTo(500,500) //画线
ctx.stroke()//填充
给线添加样式:
//draw a line with style
ctx.moveTo(0,0)//左上角
ctx.lineTo(500,500) //画线
//修改样式
ctx.lineWidth = 5
ctx.strokeStyle = "#005588"
ctx.stroke()//画线条
画多边形:只要知道顶点的坐标,调用lineTo 再画线 stoke即可
//画一个三角形
ctx.moveTo(100,100)
ctx.lineTo(500,500) //链接
ctx.lineTo(100,500)
ctx.lineTo(100,100)
//修改样式
ctx.lineWidth = 5
ctx.strokeStyle = "#005588"
ctx.stroke()//画线条
给三角形填充颜色并加上外边框
//给三角形填充
ctx.moveTo(100,100)
ctx.lineTo(500,500) //链接
ctx.lineTo(100,500)
ctx.lineTo(100,100)
ctx.fillStyle = "rgb(2,100,30)"//设置填充颜色
ctx.fill()//填充
//再给边框 但是先后顺序有影响
ctx.lineWidth = 5
ctx.strokeStyle = "red"
ctx.stroke()
绘制一个三角形 + 一条新的线
//绘制多个图形 三角形+ 另外一条线
ctx.moveTo(100,100)
ctx.lineTo(500,500) //链接
ctx.lineTo(100,500)
ctx.lineTo(100,100)
ctx.lineWidth = 5
ctx.strokeStyle = "red"
ctx.stroke()
ctx.moveTo(200,100)
ctx.lineTo(700,600)
// ctx.strokeStyle = 'black'
ctx.stroke()
//canvas基于状态绘制的 后面的同名属性会覆盖前面的
如何在上面的基础上 让三角形颜色和新的线的颜色不同? ctx.beginPath ctx.closePath
//绘制多个图形 三角形+ 另外一条线 颜色不同
ctx.beginPath()
ctx.moveTo(100,100)
ctx.lineTo(500,500) //链接
ctx.lineTo(100,500)
ctx.lineTo(100,100)
ctx.closePath()
ctx.lineWidth = 5
ctx.strokeStyle = "red"
ctx.stroke()
ctx.beginPath()
ctx.moveTo(200,100)
ctx.lineTo(700,600)
ctx.closePath()
ctx.strokeStyle = 'black'
ctx.stroke()
小结
draw 定义一个路径
- ctx.moveTo(x,y)
- ctx.lineTo(x,y)
多个路径分开处理用:
- ctx.beginPath()
- ctx.closePath()
定义线条的宽度: ctx.fillStyle = '#ccc' 和颜色: ctx.strokeStyle = 'red' 填充的颜色: ctx.fillStyle = 'rab(3,100,200)'
绘制线条
- ctx.stroke()
绘制一个填充的颜色块儿
- ctx.fill
实现需求1
-
实现一个需求的过程大概是:
-
- 需求分析,确定数据结构
-
- 确定面向过程还是面向对象?这里要求面向对象,那就面向对象
-
- 数据结构的处理(循环,赋值啥的)
-
- 事件的处理
-
- canvas基本知识的熟悉,上面已经介绍过了
-
- 基于canvas将数据和视图结合展示在页面上
-
-
代码实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<canvas id="canvas"
width="1024"
height="1024"
style="border:1px solid #aaa;
display:block;margin:0 auto"
>
浏览器不支持canvas 请更换浏览器再试
</canvas>
<script>
class Tangram{
constructor(width =800){
this.canvas = document.getElementById('canvas')
this.ctx = this.canvas.getContext('2d')
if(!this.ctx){
throw new Error('canvas不支持')
}
this.datas = [
{
p : [ {x:0,y:0}, {x:800,y:0}, {x:400, y:400}],
color: "#caff67"
},
{
p : [ {x:0,y:0}, {x:400,y:400}, {x:0, y:800}],
color: "#67becf"
},
{
p : [ {x:800,y:0}, {x:800,y:400}, {x:600, y:600}, {x:600, y:200}],
color: "#ef3d61"
},
{
p : [ {x:600,y:200}, {x:600,y:600}, {x:400, y:400}],
color: "#f9f51a"
},
{
p : [ {x:400,y:400}, {x:600,y:600}, {x:400, y:800}, {x:200, y:600}],
color: "#a594c0"
},
{
p : [ {x:200,y:600}, {x:400,y:800}, {x:0, y:800}],
color: "#fa8ecc"
},
{
p : [ {x:800,y:400}, {x:800,y:800}, {x:400, y:800}],
color: "#f6ca29"
}
]
this.WIDTH = this.HEIGHT = width
window.onload = ()=>{
this.canvas.width = this.WIDTH
this.canvas.height = this.HEIGHT
this.init()
}
}
init(){
this.datas.forEach( data => this.draw(data ,this.ctx))
}
draw(data ,ctx){
ctx.beginPath()
ctx.moveTo(data.p[0].x, data.p[0].y)
for(let i=1; i<data.p.length; i++){
ctx.lineTo(data.p[i].x, data.p[i].y)
}
ctx.closePath()
ctx.fillStyle = data.color
ctx.fill()
}
}
new Tangram()
</script>
</body>
</html>
效果:
实现需求2 用类的继承
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<canvas id="canvas"
width="1024"
height="1024"
style="border:1px solid #aaa;
display:block;margin:0 auto"
>
浏览器不支持canvas 请更换浏览器再试
</canvas>
<script>
class Tangram{
constructor(width =800){
this.canvas = document.getElementById('canvas')
this.ctx = this.canvas.getContext('2d')
if(!this.ctx){
throw new Error('canvas不支持')
}
this.datas = [
{
p : [ {x:0,y:0}, {x:800,y:0}, {x:400, y:400}],
color: "#caff67"
},
{
p : [ {x:0,y:0}, {x:400,y:400}, {x:0, y:800}],
color: "#67becf"
},
{
p : [ {x:800,y:0}, {x:800,y:400}, {x:600, y:600}, {x:600, y:200}],
color: "#ef3d61"
},
{
p : [ {x:600,y:200}, {x:600,y:600}, {x:400, y:400}],
color: "#f9f51a"
},
{
p : [ {x:400,y:400}, {x:600,y:600}, {x:400, y:800}, {x:200, y:600}],
color: "#a594c0"
},
{
p : [ {x:200,y:600}, {x:400,y:800}, {x:0, y:800}],
color: "#fa8ecc"
},
{
p : [ {x:800,y:400}, {x:800,y:800}, {x:400, y:800}],
color: "#f6ca29"
}
]
this.WIDTH = this.HEIGHT = width
window.onload = ()=>{
this.canvas.width = this.WIDTH
this.canvas.height = this.HEIGHT
this.init()
}
}
init(){
this.datas.forEach( data => this.draw(data ,this.ctx))
}
draw(data ,ctx){
ctx.beginPath()
ctx.moveTo(data.p[0].x, data.p[0].y)
for(let i=1; i<data.p.length; i++){
ctx.lineTo(data.p[i].x, data.p[i].y)
}
ctx.closePath()
ctx.fillStyle = data.color
ctx.fill()
}
}
// new Tangram()
// add Random color
class RandTangram extends Tangram{
constructor(){
super()
this.colors = ["#caff67","67becf","#ef3d61","#f9f51a","#a594c0","#fa8ecc","#f6ca29"]
this.datas = this.makeNewDatas()
}
makeNewDatas(datas){
return this.datas.map( data=>{
data.color = this.randColor()
return data
})
}
randColor(){
let index = Math.floor(Math.random() * this.colors.length )
return this.colors[index]
}
}
new RandTangram()
</script>
</body>
</html>
效果:
实现需求3 继承第二个需求的类,稍微修改即可,可以在评论区留言你的实现!!!
等你实现!!!
参考资料:
- canvas
- 波波老师的慕课网的课,他是面向过程实现的,我这里用es6面向对象实现的