1. canvas 描边、填充、画线、闭合路径、非零环绕原则

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>canvas</title>
</head>
<style>
canvas {
border: 1px solid red;
}
</style>
<body>
<canvas id="can" width="300" height="300"></canvas>
<p class="juxing">矩形</p>
<p class="triangle">三角形锯齿问题</p>
<p class="triangle2">三角形闭合没锯齿,填充色</p>
<p class="middleEmpty">中空矩形</p>
<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
<script>
let cvs = document.getElementById('can')
let ctx = cvs.getContext('2d')
$('.juxing').click(function () {
a(ctx)
})
$('.triangle').click(function () {
b(ctx)
})
$('.triangle2').click(function () {
c(ctx)
})
$('.middleEmpty').click(function () {
middleEmpty(ctx)
}) /**
* 矩形
* @param ctx
*/
function a (ctx) {
ctx.beginPath()
// 初始位置
ctx.moveTo(10, 10)
// 线条
ctx.lineTo(110, 10)
ctx.lineTo(110, 110)
ctx.lineTo(10, 110)
ctx.lineTo(10, 10)
// 描边
ctx.stroke()
} /**
* 等腰三角形 ,继续画解决锯齿
* @param ctx
*/
function b (ctx) {
ctx.beginPath()
ctx.moveTo(110, 10) ctx.lineTo(160, 60)
/* 这些线条接着画不会出现锯齿*/
ctx.lineTo(60, 60)
ctx.lineTo(110, 10) // 解决锯齿
ctx.lineTo(160, 60)
/* 这里也要接下继续画取消底点锯齿*/ // 线条颜色设置,必须放在绘制之前 ctx.strokeStyle = css任意的颜色表示
ctx.strokeStyle = 'blue'
// 线宽设置,必须放在绘制之前
ctx.lineWidth = 6 ctx.stroke()
} /**
* 闭合路径:
* 从当前路径的起点点到结束点连一条路径。
* ctx.closePath()
* 图形可以省去最后一条边,也解决了锯齿
* @param ctx
*/
function c (ctx) {
ctx.beginPath() // 清除当前路径,开启新路径,解决了所有图片颜色覆盖问题
ctx.moveTo(110, 10)
ctx.lineTo(160, 60)
ctx.lineTo(60, 60)
// 有了closePath,绘图直线图形时,最后一条边就可以省去了
ctx.closePath() ctx.strokeStyle = 'yellow'
// 线宽设置,必须放在绘制之前
ctx.lineWidth = 6
ctx.fillStyle = 'red' // 填充色
ctx.fill() // 填充 默认黑色
ctx.stroke()
} /*
* 非零环绕原则:
* 是用来判断哪些区域属于路径内( 计算结果非0,即为路径内,有填充色 )。
* 在路径包围的区域中,随便找一点,向外发射一条射线,
* 和所有围绕它的边相交,
* 然后开启一个计数器,从0计数,
* 如果这个射线遇到顺时针围绕,那么+1,
* 如果遇到逆时针围绕,那么-1,
* 如果最终值非0,则这块区域在路径内。
*
* 备注:基数边的区域一定在路径内,有填充色。(画线过程体现出图形的方向)
* */ // 封装一个绘制矩形的函数
function juXing (startX, startY, width, height, lineWidth, strokeStyle, fillStyle) { ctx.moveTo(startX, startY)
ctx.lineTo(startX + width, startY)
ctx.lineTo(startX + width, startY + height)
ctx.lineTo(startX, startY + height)
ctx.closePath() ctx.lineWidth = lineWidth
ctx.strokeStyle = strokeStyle
ctx.fillStyle = fillStyle /*
* 描边的时候,会占用原图形的一部分( 线宽的一半 )。
* 所以,日常开发中,为了让线宽符合要求,
* 最好先填充,再描边,防止填充时覆盖掉线宽的一半。
* */ ctx.fill()
ctx.stroke()
} /**
* 中间空的填充矩形
* 两个矩形 一个逆时针画,一个顺时针画,
* 最中间部分,根据非零环绕原则等于0,则是在路径外,无填充色
* @param ctx
*/
function middleEmpty (ctx) {
// 顺时针画一个大矩形
juXing(10, 10, 100, 100, 6, 'skyblue') // 逆时针画一个小矩形
ctx.moveTo(35, 35)
ctx.lineTo(35, 55)
ctx.lineTo(55, 55)
ctx.lineTo(55, 35)
// 顺 -> 两个都是顺时针的话,全都被填充了
/* ctx.moveTo( 35, 35 );
ctx.lineTo( 55, 35 );
ctx.lineTo( 55, 55 );
ctx.lineTo( 35, 55 );*/
ctx.lineWidth = 3
ctx.strokeStyle = 'blue'
ctx.closePath()
ctx.stroke() // 一起填充
ctx.fillStyle = 'red'
ctx.fill()
} </script>
</body>
</html>

2.canvas 线帽(线顶点)、线连接点、矩形api,清空画布,渐变矩形(一堆线加上 rgb线条颜色 )

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>canvas</title>
</head>
<style>
canvas {
border: 1px solid red;
} p {
border: 2px solid blue;
padding:10px;
margin-right: 10px;
}
</style>
<body>
<canvas id="can" width="300" height="300"></canvas>
<div style="display: flex;">
<p class="juxing">线帽(线顶点)lineCap</p>
<p class="triangle">线连接点 lineJoin</p>
<p class="triangle2">矩形api</p>
<p class="middleEmpty">清空画布</p>
<p class="bian">渐变矩形</p>
</div>
<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
<script>
let cvs = document.getElementById('can')
let ctx = cvs.getContext('2d')
$('.juxing').click(function () {
a(ctx)
})
$('.triangle').click(function () {
b(ctx)
})
$('.triangle2').click(function () {
c(ctx)
})
$('.middleEmpty').click(function () {
d(ctx, cvs)
})
$('.bian').click(function () {
lineGarden(ctx)
}) /*
* 设置线帽样式:
* ctx.lineCap = ‘butt' 、'round'、'square'
* butt是默认值,
* round线头是圆的,多了两个半径出来,比默认的长
* square线头两段各增加线宽的一半,比默认的长
* */ function a (ctx) { ctx.beginPath() // 防止 stroke 重绘之前的路径 默认 stroke 会生成所有路径
// canvas在绘制线条的时候,会向左向右偏移线宽的一半,然后进行绘制。
// 如果线宽为奇数,那么边缘的颜色值,会缩减一半(调整线条粗细看效果)。
ctx.lineWidth = 10 // 默认线头
ctx.moveTo(10, 10)
ctx.lineTo(210, 10)
ctx.stroke() ctx.beginPath()
ctx.lineCap = 'square' // 增长线头,两端各增长线宽的一半
// ctx.lineCap = 'round'; // 圆线头,两端的圆半径为线宽的一半
ctx.moveTo(10, 30)
ctx.lineTo(210, 30)
ctx.stroke()
} /*
* 设置线连接点样式:
* ctx.lineJoin = ‘miter' 、'round'、'bevel'
* miter是默认值,两边向外延伸相交为尖尖角,
* round是圆头,
* bevel两边相连为一个斜面。
* */
function b (ctx) {
ctx.beginPath()
ctx.lineWidth = 10 // 默认交点为尖尖角
ctx.lineJoin = 'miter'
ctx.moveTo(10, 10)
ctx.lineTo(60, 110)
ctx.lineTo(110, 10)
ctx.stroke() ctx.beginPath()
ctx.lineJoin = 'round' // 交点为圆头
// ctx.lineJoin = 'bevel'; // 交点为斜面
ctx.moveTo(10, 50)
ctx.lineTo(60, 150)
ctx.lineTo(110, 50)
ctx.stroke() } function c (ctx) {
ctx.beginPath()
/*
* 画一个矩形路径:
* ctx.rect( 起点x轴坐标,起点y轴坐标,宽,高 );
* */
ctx.rect(30, 10, 50, 50)
ctx.stroke() /*
* 绘制一个描边矩形,这个方法不会产生任何路径:
* ctx.strokeRect( 起点x轴坐标,起点y轴坐标,宽,高 )
* */
ctx.strokeRect(30, 100, 50, 50) /*
* 绘制一个填充矩形,这个方法不会产生任何路径:
* ctx.fillRect( 起点x轴坐标,起点y轴坐标,宽,高 )
* */
ctx.fillRect(30, 170, 50, 50) } function d (ctx, cvs) {
/*
* 按照矩形的大小来清除画布中指定位置的内容:
* ctx.clearRect( 起点x轴坐标,起点y轴坐标,宽,高 );
* */
ctx.clearRect(0, 0, cvs.width, cvs.height) } /* 渐变矩形 画一堆横线,加上rgb 线条*/
function lineGarden (ctx) {
// 需求,在50,50点绘制一个宽高各100的渐变矩形
var i = 0, len = 100
for (; i < len; i++) {
// 为了防止重绘
ctx.beginPath()
ctx.moveTo(50, 50 + i)
ctx.lineTo(150, 50 + i)
// 红色通道值依次累加
ctx.strokeStyle = 'rgb(' + 0 + ', ' + Math.floor(255 / 99 * i) + ', ' + 255 + ' )'
// ctx.strokeStyle = 'rgb(' + 0 + ', ' + i + ', ' + 255 + ' )';
ctx.stroke()
}
}
</script>
</body>
</html>

3. canvas 折线图

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
canvas {
border: 1px solid red;
}
</style>
</head>
<body>
0.各部分都可单独研究绘画细节
1.定义坐标轴距离画布上下左右的边距
定义线条粗细
2.求横坐标原点,x轴顶点,y轴顶点坐标,并画x/y轴
3.定义箭头的宽高,把箭头当成一个矩形,放大可看细节,并填充
4.画任意点,把点当成矩形来画 fillRect() 宽高为2,为1的话颜色太浅, 宽高可以适当变大变小
5.画折线,连接的点实际上连接的是小矩形的左上角顶点,要偏移一下坐标,坐标偏移小矩形宽高的一半,使线穿过小矩形的中心
6.计算 x/y轴的长度,计算数据的缩放比例
7.[1,5640,654,2,2,6,5,3,56] 根据y轴的缩放比例来修改原数据,根据x轴的缩放比例来显示各个点的间距 <canvas id="cvs" width="500" height="500"></canvas>
<script>
var cvs = document.getElementById('cvs');
var ctx = cvs.getContext('2d'); ctx.lineWidth = 2; // 坐标轴距离画布上右下左的边距
var padding = {
top: 20,
right: 20,
bottom: 20,
left: 20
} // 坐标轴中箭头的宽和高
var arrow = {
width: 12,
height: 20
} // 求坐标轴上顶点的坐标
var vertexTop = {
x: padding.left,
y: padding.top
} // 求坐标轴原点的坐标
var origin = {
x: padding.left,
y: cvs.height - padding.bottom
} // 求坐标轴右顶点的坐标
var vertexRight = {
x: cvs.width - padding.right,
y: cvs.height - padding.bottom
} // 画坐标轴中的两条线
ctx.moveTo( vertexTop.x, vertexTop.y );
ctx.lineTo( origin.x, origin.y );
ctx.lineTo( vertexRight.x, vertexRight.y );
ctx.stroke(); // 画上顶点箭头
ctx.beginPath();
ctx.moveTo( vertexTop.x, vertexTop.y );
ctx.lineTo( vertexTop.x - arrow.width / 2, vertexTop.y + arrow.height );
ctx.lineTo( vertexTop.x, vertexTop.y + arrow.height / 2 );
ctx.lineTo( vertexTop.x + arrow.width / 2, vertexTop.y + arrow.height );
ctx.closePath();
ctx.fill(); // 画右顶点箭头
ctx.beginPath();
ctx.moveTo( vertexRight.x, vertexRight.y );
ctx.lineTo( vertexRight.x - arrow.height, vertexRight.y - arrow.width / 2 );
ctx.lineTo( vertexRight.x - arrow.height / 2, vertexRight.y );
ctx.lineTo( vertexRight.x - arrow.height, vertexRight.y + arrow.width / 2 );
ctx.closePath();
ctx.fill(); // 求坐标轴默认可显示数据的最大值
coordMaxX = cvs.width - padding.left - padding.right - arrow.height;
coordMaxY = cvs.height - padding.top - padding.bottom - arrow.height; /*
* 在坐标轴中指定位置画点,坐标算法:
* 点的x轴:原点x坐标 + 点到原点的水平距离
* 点的y轴:原点y坐标 - 点到原点的垂直距离
* */ // 需求,利用折线图的方式展示一下门口大爷酱香饼每日销售量
// [ 10, 20, 50, 80, 120, 300, 100, 50, 2 ]; var data = [ 100, 200, 400, 600, 1200, 1800, 1000, 500, 20 ]; // 求数据缩放的比例
var ratioX = coordMaxX / data.length;
var ratioY = coordMaxY / Math.max.apply( null, data ); // 根据比例,对元数据进行缩放
var ratioData = data.map( function( val, i ) {
return val * ratioY;
}); // 画点
ratioData.forEach( function( val, index ) {
ctx.fillRect( origin.x + ( index * ratioX) - 2, origin.y - val - 2, 4, 4 );
}); // 画折线
ctx.beginPath();
ratioData.forEach( function( val, index ) {
ctx.lineTo( origin.x + ( index * ratioX), origin.y - val );
});
ctx.stroke();
</script>
</body>
</html>

4. canvas 饼图

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
canvas {
border: 1px solid red;
}
p{
line-height: 30px;
margin:0;
}
</style>
</head>
<body>
<p>混入式继承,换种方式的原型继续 Person.prototype={}</p>
画扇形 <br/>
<p>1.计算数据占的比例 i/sum*360度</p>
<p>2. 度数转为弧度</p>
<p>3.每一个扇形的开始弧度等于上一个扇形的结束弧度
每一个扇形的结束弧度等于上一个扇形的结束弧度+所占的弧度</p>
<p>4. 画扇形 填充</p>
<p>5.0计算扇形平分线的坐标(即圆上点的坐标)</p>
<p>5.1画平分线,并延长(延长半径,则平分钱也延长了)并填充颜色,覆盖点扇形内的线</p>
<p>6绘制文字</p>
<canvas id="cvs" width="500" height="500"></canvas>
<script>
(function (w) { // 把角度转换为弧度
function angleToRadian (angle) {
return Math.PI / 180 * angle
} // 混入式继承
function extend (o1, o2) {
for (var key in o2) {
// 只有o2自己的属性才会copy到o1身上
if (o2.hasOwnProperty(key)) {
o1[key] = o2[key]
}
}
} /*
* constrcutor { Pipe } 饼图构造函数
* param { x: number } 圆心x轴坐标
* param { y: number } 圆心y轴坐标
* param { r: number } 圆半径
* param { data: Array } 绘制饼图所需的数据
* */
function Pipe (x, y, r, data) { this.x = x
this.y = y
this.r = r
this.data = data // 一组颜色
this.colors = ['orange', 'orchid', 'palegoldenrod', 'palegreen', 'paleturquoise', 'peru', 'pink']
} // 给原型扩充方法
extend(Pipe.prototype, { // 绘制饼图
draw: function () { // 在外面保存一下this
var self = this // 数据的总和
var num = 0
this.data.forEach(function (obj) {
num += obj.val
}) // 一个数据值所占用的角度
var baseAngle = 360 / num // 假设一开始就绘制了一个起始为0,结束为0的扇形
var startAngle = 0,
endAngle = 0,
lineAngle = 0,
lineX, lineY // 画扇形
this.data.forEach(function (obj, i) { // 每次进来,计算当前扇形的起始角度和结束角度 // 下一个扇形的起始角度,是当前扇形的结束角度
startAngle = endAngle
// 这个结束角度 = 上一个扇形的结束角度 + 当前数值所对应的角度
endAngle = endAngle + baseAngle * obj.val // 求扇形中间线的角度
lineAngle = startAngle + baseAngle * obj.val / 2;
/*
* 根据中间线的角度,求中间的线的x和y坐标:
* x = 圆心x + r * Math.cos( angleToRadian( pointAngle ) )
* y = 圆心y + r * Math.sin( angleToRadian( pointAngle ) )
* */
lineX = self.x + ( self.r + 20 ) * Math.cos( angleToRadian( lineAngle ) );
lineY = self.y + ( self.r + 20 ) * Math.sin( angleToRadian( lineAngle ) ); // 第一个扇形
ctx.beginPath()
ctx.moveTo(self.x, self.y)
ctx.arc(self.x, self.y, self.r, angleToRadian(startAngle), angleToRadian(endAngle))
ctx.closePath()
ctx.fillStyle = self.colors[i]
ctx.fill() // 画每一个扇形的平分线
ctx.beginPath();
ctx.moveTo( self.x, self.y );
ctx.lineTo( lineX, lineY );
ctx.strokeStyle = self.colors[ i ];
ctx.stroke(); // 绘制文字
if ( lineAngle >= 90 && lineAngle <= 270 ) {
ctx.textAlign = 'right';
}else {
ctx.textAlign = 'left';
}
ctx.fillText( obj.msg, lineX, lineY );
})
}
}) // 把构造函数暴露到全局
w.Pipe = Pipe }(window)); var cvs = document.getElementById('cvs')
var ctx = cvs.getContext('2d') // var pipe = new Pipe( 200, 200, 80, [ 10, 30, 50, 60, 20 ] );
// [ 10, 30, 50, 60, 20 ]
var pipe = new Pipe(200, 200, 80, [
{
val: 10,
msg: '米饭'
},
{
val: 30,
msg: '面条'
},
{
val: 50,
msg: '馒头'
},
{
val: 50,
msg: '豆腐脑'
},
{
val: 50,
msg: '饺子'
},
{
val: 90,
msg: '汤圆'
},
])
pipe.draw() </script>
</body>
</html>

5.canvas 生成图片、画弧、扇形、文字

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>canvas</title>
</head>
<style>
canvas {
border: 1px solid red;
} p {
border: 2px solid blue;
padding: 10px;
margin-right: 10px;
}
</style>
<body>
<canvas id="can" width="300" height="300"></canvas>
<div style="display: flex;">
<p class="juxing">虚线 setLineDash 生成图片 canvas.toDataUrl('image/png')</p>
<p class="triangle">画弧</p>
<p class="triangle2">扇形</p>
<p class="middleEmpty">清空画布</p>
<p class="bian">文字</p>
</div>
<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
<script>
let cvs = document.getElementById('can')
let ctx = cvs.getContext('2d')
$('.juxing').click(function () {
a(ctx, cvs)
})
$('.triangle').click(function () {
b(ctx)
})
$('.triangle2').click(function () {
c(ctx)
})
$('.middleEmpty').click(function () {
d(ctx, cvs)
})
$('.bian').click(function () {
e(ctx)
}) /*
* 设置画线的时候空白部分和实线部分的大小。
* ctx.setLineDash( [ 5, 3 ] )
* 参数可以任意多个
* */ function a (ctx, cvs) {
ctx.beginPath() ctx.lineDashOffset = 3 // 设置偏移量,进行微调用,效果不明显
ctx.setLineDash([5, 3]) // 5像素实线,3像素空白,则变成了虚线
ctx.moveTo(10, 10)
ctx.lineTo(210, 10)
ctx.stroke() let url = cvs.toDataURL('image/png')
let img = document.createElement('img')
img.src = url
document.body.appendChild(img)
/*
* 获取线条绘制规则。
* ctx.getLineDash()
* */
console.log(ctx.getLineDash())
} /*
* 画弧( 画的是路径 )
* ctx.arc( 圆心x轴坐标,圆心y轴坐标,半径, 起点弧度,结束点弧度,是否逆时针画(可选) )
* arc方法内部会先从路径结束点到弧的起点画一条路径线。
* 起点弧度、结束点弧度以及弧度的方向共同决定了弧的大小。
* */
// 把角度转换为弧度
function angleToRadian (angle) {
return Math.PI / 180 * angle
} function b (ctx) {
ctx.beginPath()
// 顺时针画一段弧 从x轴水平线右侧开始 默认顺时针
ctx.arc(100, 100, 30, angleToRadian(90), angleToRadian(270))
ctx.stroke()
// 逆时针画一段弧
ctx.beginPath()
ctx.arc(200, 100, 30, angleToRadian(90), angleToRadian(270), true)
ctx.stroke()
} function c (ctx) {
ctx.beginPath()
/*
* 画扇形:
* 1、先设置路径起点为圆心
* 2、画弧
* 3、闭合路径
* */
ctx.beginPath()
ctx.moveTo(100, 100) // arc方法内部会先从路径结束点到弧的起点画一条路径线。
ctx.arc(100, 100, 90, angleToRadian(220), angleToRadian(310))
ctx.closePath()
ctx.stroke()
} function d (ctx, cvs) {
ctx.clearRect(0, 0, cvs.width, cvs.height)
ctx.setLineDash([]) // 清空虚线
} /*
* 设置文字的属性
* ctx.font = 和css语法一样。
* 注意:这里设置字体大小时必须带单位,单位支持css的所有表示方式。
* 注意:单独设置字体大小不会生效,必须要加一个额外属性样式。 ctx.strokeText( 描边文字, 参考x轴坐标,参考y轴坐标,限制文字的最大长度(可选) )
ctx.fillText( 填充文字, 参考x轴坐标,参考y轴坐标,限制文字的最大长度(可选) ) * 设置文字的水平对其方式:
* ctx.textAlign = 'left || start' 、 'right || end' 、 'center'
* 默认值为start。 * 设置文字的垂直对其方式:
* ctx.textBaseline = 'top' 、'bottom'、'middle'、'alphabetic'、'hanging'、'ideographic'
* 默认值为alphabetic。
* */
function e (ctx) {
ctx.beginPath()
// ctx.font = '3rem 微软雅黑'
ctx.font = '28px 微软雅黑'
ctx.fillStyle = 'deeppink'; ctx.textAlign = 'left' // 水平对齐
ctx.textBaseline = 'middle' // 垂直对齐
ctx.strokeText('描边字', 100, 100) // 描边文字,空心字
// ctx.strokeText('中文字',100,100,100) // 第一个参数限制文字宽度,小了则压缩字体
ctx.fillText('中文字', 200, 200) // 填充文字,一般字 // 绘制文字的参考点
ctx.beginPath()
ctx.arc(100, 100, 4, 0, Math.PI * 2)
ctx.fill() // 在画布的左上角绘制一段文字
ctx.textAlign = 'left';
ctx.textBaseline = 'top';
ctx.fillText( '左上角', 0, 0 ); // 在画布的右上角绘制一段文字
ctx.textAlign = 'right';
ctx.textBaseline = 'top';
ctx.fillText( '右上角', cvs.width, 0 ); }
</script>
</body>
</html>

6. canvas drawImage() 三参数、五参数、九参数、

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>canvas</title>
</head>
<style>
canvas {
border: 1px solid red;
}
</style>
<body>
<img src="NPC5.png" alt="" id="img"> <!-- 160*260 -->
<canvas id="can" width="300" height="360"></canvas>
<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
<script>
let cvs = document.getElementById('can')
let ctx = cvs.getContext('2d')
// 直接画,避开函数调用产生的异步问题
/*
* ctx.drawImage()
* 绘制图像,有三种使用方式。
* 三参数 图像、坐标x,坐标y
* 五参数 图像、坐标x,坐标y, 图片宽,图片高
* 九参数 把裁剪到的部分图像绘制到指定的坐标,并指定其大小。
* drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh)
* sx, sy, sw, sh 切原图一小块的坐标宽高
* dx,dy,dw,dh 是最终图片的坐标,宽高
* */ let img = document.getElementById('img')
img.onload = function () {
// ctx.drawImage(img, 10, 10)
// ctx.drawImage(img, 10, 100, img.width, img.height) // drawImage(image, dx, dy)
// drawImage(image, dx, dy, dw, dh)
// drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh) ctx.drawImage(img, 0, img.height / 4 * 2, img.width / 4, img.height / 4,
40, 140, img.width / 4, img.height / 4) let i = 0, step = 0
let interval = setInterval(() => {
ctx.clearRect(80, 140, cvs.width, cvs.height)
ctx.drawImage(img, img.width / 4 * i, img.height / 4, img.width / 4, img.height / 4,
180 - step * 5, 140, img.width / 4, img.height / 4)
i++
step++
if (i > 3) {
i = 0
}
if (180 - step * 5 < 80) {
window.clearInterval(interval)
}
}, 100)
}
</script>
</body>
</html>

7.canvas 平移 translate、旋转 rotate、缩放 scale

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
canvas {
border: 1px solid red;
}
</style>
</head> <body>
<canvas width="300" height="300" id="can"></canvas>
<script>
let cvs = document.getElementById('can')
let ctx = cvs.getContext('2d') /*
* 平移,移动原来的矩形
* 平移、缩放、旋转会叠加
* */
ctx.fillRect(30, 30, 20, 20)
ctx.translate(20, 20)
ctx.fillStyle = 'blue'
ctx.fillRect(30, 30, 20, 20) /*
* 旋转 相对于原点的旋转
* 先平移到中间某位置
* */
ctx.translate(100, 100)
ctx.fillRect(0, 0, 30, 30) // 从 (0,0)开始 ctx.rotate(Math.PI / 6)
ctx.fillStyle = 'red'
ctx.fillRect(0, 0, 30, 30) ctx.rotate(Math.PI / 6)
ctx.fillStyle = 'pink'
ctx.fillRect(0, 0, 30, 30) /*
* 缩放 相对于原点的缩放
* 先平移到中间某位置
* 最好单独试,免得叠加计算出错
*
* */
ctx.rotate(-Math.PI / 6*2) // 旋转回来
ctx.translate(60, 60)
ctx.fillRect(0, 0, 40, 40)
ctx.scale(0.5, 0.5)
ctx.fillStyle = 'blue'
ctx.fillRect(0, 0, 40, 40) </script>
</body>
</html>

8.工厂模式 函数返回时   return new Person(name,age)

 /* 工厂模式 */
function Person (name, age) {
this.name = name
this.age = age
} // 工厂
// 工厂模式相当于省去new关键字
function getPerson (name, age) {
return new Person(name, age)
} console.log(getPerson('女神', 18))

9.状态保存、回滚 ctx.save()   ctx.restore()   判断点在画布中, 旋转图形绘制(第9不太懂)

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>canvas</title>
</head>
<style>
canvas {
border: 1px solid red;
} p {
border: 2px solid blue;
padding: 10px;
margin-right: 10px;
}
</style>
<body>
<canvas id="can" width="300" height="360"></canvas>
<div style="display: flex;">
<p class="juxing">状态保存、回滚 ctx.save() restore()</p>
<p class="triangle">判断点在画布中</p>
</div>
<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
<script>
let cvs = document.getElementById('can')
let ctx = cvs.getContext('2d') /*
* 绘制一个旋转图形的步骤:
* 1、先平移坐标轴到图形的中心
* 2、旋转坐标轴
* 3、绘制图形( 需要注意,平移旋转之后,坐标体系变化,不能按照之前定好的坐标来绘制旋转图形 )
* */ /* // 正常情况下的参考矩形
ctx.fillStyle = 'pink';
ctx.fillRect( 100, 100, 50, 50 ); // 原来的图形 // 平移到矩形的中心
ctx.translate( 125, 125 );
// 旋转坐标系
ctx.rotate( Math.PI / 180 * 30 );
// 绘制图形
ctx.fillStyle = 'blue';
ctx.fillRect( -25, -25, 50, 50 ); // 新坐标为宽高的一半,不懂。*/ // 定时器
// 先统一平移到矩形的中心
ctx.translate(125, 125)
// 基于这个中心不断绘制旋转矩形
setInterval(function () {
// 清除上一次的矩形
ctx.clearRect(-50, -50, cvs.width, cvs.height)
// 旋转坐标系
ctx.rotate(Math.PI / 180 * 4)
// 绘制图形
ctx.fillRect(-25, -25, 50, 50)
}, 50) /* 工厂模式 */
function Person (name, age) {
this.name = name
this.age = age
} // 工厂
// 工厂模式相当于省去new关键字
function getPerson (name, age) {
return new Person(name, age)
} console.log(getPerson('女神', 18)) /**
* 状态保存: ctx.save();
* 状态回滚: ctx.restore();
* */
$('.juxing').click(function () {
// 保存下面的状态
ctx.save()
ctx.lineWidth = 10
ctx.strokeStyle = 'blue' ctx.moveTo(10, 10)
ctx.lineTo(210, 10)
ctx.stroke() // 再保存下面的状态
ctx.save()
ctx.strokeStyle = 'green' ctx.beginPath()
ctx.moveTo(10, 60)
ctx.lineTo(210, 60)
ctx.stroke() // 回滚
ctx.restore()
ctx.beginPath()
ctx.moveTo(10, 90)
ctx.lineTo(210, 90)
ctx.stroke() }) $('.triangle').click(function () {
/*
* 判断点在不在路径中:
* ctx.isPointInPath( 要判断的点x轴坐标,要判断的点y轴坐标 )
* */ ctx.rect(10, 10, 50, 50)
ctx.stroke() // 点击画布,判断点击的位置在不在路径中
cvs.addEventListener('click', function (e) {
var x = e.pageX - cvs.offsetLeft
var y = e.pageY - cvs.offsetTop
alert(ctx.isPointInPath(x, y))
}) }) </script>
</body>
</html>

10 监听者模式(不懂)

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script> // 一个监听者 服务与 多个听众
// 监听者
var jianTingZhe = { // 听众列表
listeners: {
birdOver: [],
birdFlappy: [],
birdRotate: []
}, // 小鸟死亡触发时,告知所有监听死亡的听众
triggerBirdOver: function() {
this.listeners.birdOver.forEach( function( listen ) {
listen();
});
}, // 小鸟飞翔的时候,告知所有监听飞翔的听众
triggerBirdFlappy: function() {
this.listeners.birdFlappy.forEach( function( listen ) {
listen();
});
}, // 小鸟飞翔的时候,告知所有监听飞翔的听众
triggerBirdRotate: function() {
this.listeners.birdRotate.forEach( function( listen ) {
listen();
});
} }; // 这是一个模块,整体可以认为是一个听众监听N多事件
(function( w ) {
// 小鸟死亡听众
jianTingZhe.listeners.birdOver.push( function() {
console.log( '小鸟死了,我就哭' );
} );
jianTingZhe.listeners.birdOver.push( function() {
console.log( '小鸟死了,我很伤心' );
} );
jianTingZhe.listeners.birdOver.push( function() {
console.log( '小鸟死了,我要埋葬它' );
} ); // 小鸟飞翔听众
jianTingZhe.listeners.birdFlappy.push( function() {
console.log( '小鸟飞了,我很搞笑' );
});
jianTingZhe.listeners.birdFlappy.push( function() {
console.log( '小鸟飞了,我要把射下来' );
}); // 小鸟旋转听众
jianTingZhe.listeners.birdRotate.push( function() {
console.log( '小鸟转了,呱唧呱唧!' );
});
}( window )); // 这是另一个模块,整体可以认为是一个听众
(function( w ) {
// 小鸟旋转听众
jianTingZhe.listeners.birdRotate.push( function() {
console.log( '我是模块2' );
});
}( window )); // 监听到小鸟死了
jianTingZhe.triggerBirdOver();
// 监听到小鸟转了
jianTingZhe.triggerBirdRotate()
// 监听到小鸟飞翔了
jianTingZhe.triggerBirdFlappy()
</script>
</body>
</html>

11.动画帧函数  requestAnimationFrame 函数回调的触发是由浏览器来控制的,行就会比较稳定,适合用来做流畅的动画。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
div {
height: 20px;
background-color: black;
}
</style>
</head>
<body>
<div id="div"></div>
<script>
/*
* 请求动画帧函数,这个函数和setTimeout方法使用类似,
* 他都是定时器,却别在于setTimeout可以自由指定回调的触发时间,
* 而requestAnimationFrame函数回调的触发是由浏览器来控制的。
*
* requestAnimationFrame( callback )
* 备注:当浏览器重绘页面的时候,就会调用这个callback,
* 这样callbackg的执行就会比较稳定,适合用来做流畅的动画。
* */ /*setInterval( function() {
console.log(111);
}, 50);*/ /*function con() {
console.log(111);
setTimeout( con, 50);
}
setTimeout( con, 50);*/ // 简化setTimeout不断执行回调的方式
/*(function con() {
console.log(111);
setTimeout( con, 50);
}());*/ // 把setTimeout改为requestAnimationFrame
(function con() {
console.log(111);
requestAnimationFrame( con );
}());
</script>
</body>
</html>

12. ctx2.drawImage( cvs1, 0, 0 );  // 把第一个canvas的内容绘制到第二个canvas中

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
div {
height: 20px;
background-color: black;
}
</style>
</head>
<body>
<canvas id="cvs1"></canvas>
<canvas id="cvs2"></canvas>
<script>
/*
* drawImage的第一个参数可以是img、canvas或video
* */ var cvs1 = document.querySelector( '#cvs1' );
var cvs2 = document.querySelector( '#cvs2' ); var ctx1 = cvs1.getContext( '2d' );
var ctx2 = cvs2.getContext( '2d' ); // 给第一个画布绘制内容
ctx1.fillRect( 10, 10, 100, 100 ); // 把第一个canvas的内容绘制到第二个canvas中
ctx2.drawImage( cvs1, 0, 0 );
ctx2.fillStyle = 'blue';
ctx2.fillRect( 0, 0, 50, 50 ); </script>
</body>
</html>

 

canvas20181114的更多相关文章

随机推荐

  1. 普通工程转为mvn工程

    不同类型的工程可以转为mvn工程, 只需要一个插件 You may need to install m2e-eclipse plugin in order to have this simple ut ...

  2. 把url后面的.html去掉

    $url = "http://haichuang1997.bmlink.com/supply/dc_355472.html";echo rtrim($url, '.html');

  3. 算法(Python)

    算法就是为了解决某一个问题而采取的具体有效的操作步骤 算法的复杂度,表示代码的运行效率,用一个大写的O加括号来表示,比如O(1),O(n) 认为算法的复杂度是渐进的,即对于一个大小为n的输入,如果他的 ...

  4. apache基础

    apache基于多域名的虚拟主机 NameVirtualHost *:80<VirtualHost *:80> DocumentRoot "/var/www/html/xk/sh ...

  5. Vue学习——使用vue-cli搭建一个简单的本地vue项目

    前提 安装好node.js.npm.vue-cli.为什么要先安装这些,建议查看https://www.cnblogs.com/jixue/p/10673875.html,这个对于vue-cli理解很 ...

  6. hdu1213并查集

    板子题不多说,上代码 #include<iostream> #include<cstdio> #include<cstring> using namespace s ...

  7. ngui处理不规则按钮点击

    吐个槽  棋牌类游戏做什么中国地图!!!  然后就要用到不规则按钮点击了 你懂的 213的unity虽然已经加入了polygoncollider 2d的支持 但是 但是 但是 是2d的 也就是说如果不 ...

  8. Spread Syntax

    [Spread Syntax] The spread syntax allows an expression to be expanded in places where multiple argum ...

  9. Java 调用系统命令

    ProcessBuilder import java.io.File; import java.io.IOException; import java.io.InputStream; import j ...

  10. 2N7002

    就相当于一个开关,当G>S的一定电压就导通,若没有达到就没有导通. 并且注意的是D脚不能直接接电压,中间要接一个电阻. 这用是G输入,S接地,D输出. 跟三极管差不多.分N和P