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. HFSS在进行仿真时端口与激励设置细则

    最近发现在使用HFSS仿真天线时候在设置端口激励求解的时候,由于端口激励面积的大小和放置方式的不通最终的求解结果也有很多不同 在进行CPW结构的天线仿真中分别尝试了waveport 和lumpedpo ...

  2. vue+elementUI+axios实现的全局loading加载动画

    在项目中,很多时候都需要loading加载动画来缓解用户的焦虑等待,比如说,我打开了一个页面,而这个页面有很多接口请求,但浏览器的请求并发数就那么几个,再加上如果网速不行的话,那么这时候,用户很可能就 ...

  3. http 400错误【原】

    http 400错误现象: 使用java代码访问某PDF文件地址, 报了http 400错误 ,浏览器却能正常访问 . 所以猜测浏览器对地址做了额外处理. 异常代码 String srcUrl = & ...

  4. js/vue图片压缩

    js版 新建compressImage.js,内容如下: // 将base64转换为blob(有需要可加上,没需要可不加) function convertBase64UrlToBlob(urlDat ...

  5. important的妙用解决firefox和ie的css兼容问题

    设置css的min-height属性.min-height在Firefox里有效,但IE无法识别.下面有个不错的解决方案,大家可以参考下 对于某些内容可变的层(比如用户评论),我们希望它有个最小的高度 ...

  6. 从Word Embedding到Bert模型—自然语言处理中的预训练技术发展史(转载)

    转载 https://zhuanlan.zhihu.com/p/49271699 首发于深度学习前沿笔记 写文章   从Word Embedding到Bert模型—自然语言处理中的预训练技术发展史 张 ...

  7. 413 重温HTML + css 考试 + 访问HTML元素

    考试前的复习 初学css1:认识CSS 1.1:css简介,css全称是层叠样式表,Cascading style sheets 1.2:css的作用,主要是用于定义html内容在浏览器内的显示样式, ...

  8. iTOP-4412/4418/6818开发板-fastboot烧写脚本

    在 iTOP-4412,4418,6818 开发板烧写的时候,使用的是 fastboot 工具. fastboot 工具需要在 cmd.exe 中调用,每次都需要输入烧写命令,这样步骤有点多.在程序员 ...

  9. [经验交流] kubeadm 安装 kubernetes 一年过期的解决办法

    kubeadm 是 kubernetes 提供的一个初始化集群的工具,使用起来非常方便.但是它创建的apiserver.controller-manager等证书默认只有一年的有效期,同时kubele ...

  10. 很好用的电脑桌面远程控制软件 支持多平台 Win,Mac,Debian… 等操作系统 Anydesk

    很好用的电脑桌面远程控制软件 支持多平台 Win,Mac,Debian, Ubuntu, FreeBSD… 等操作系统 Anydesk 官网下载地址:https://anydesk.com/remot ...