Canvas
canvas 是HTML5新出的标签,可以用来做小游戏,特效,作图等,自己并没有作画能力,只能通过Javascript脚本来操控
Canvas标准
http://www.w3c.org/TR/2dcontext/ https://html.spec.whatwg.org/
创建Canvas
创建canvas几个主要的问题:
1.不能通过CSS设置画布的大小,否则会造成画布拉伸变形等问题,只能设置本身自带width、height属性,也可以在js里设置
2.兼容性:对一些不支持的浏览器,可以在标签内输入提示,不支持的浏览器会显示此提示、支持的浏览器会自动忽略掉
3.创建并设置好宽高后,通过js获取,还要设置其getContext,成功返回一个对象后即可作画,这里用js也可判断其是否支持canvas
语法格式:
代码语言:javascript复制<canvas width="1024" height="570" class="canvas">由于您的浏览器版本过低,此图片不能加载</canvas>
<script>
var ctx = document.querySelector(".canvas").getContext("2d|3d");
</script>
手册参考网址
线
画布的x、y起点默认在右上角的位置(0,0), 分别对应的最大值是画布的宽和高
绘制线条的函数:
moveTo(x,y) : 开始位置
lineTo(x,y):结束位置
stroke :准备好后,开始画线条
设置线条样式的函数:
lineWidth:设置线条粗细
strokeStyle:设置线条的颜色
lineCap:设置线条首尾处的形状 俗称帽子
lineJoin:设置连接处的样式
miterLimit:内角与外角的距离。默认值是10,此属性只有在lineJoin = “miter”并且有设置线条粗细情况下才有效,且斜接长度大于miterLimit ,线条连接处自动斜切(lineJoin =”bevel”)
另起一条路径的函数:
beginPath:起始一条路径,或重置当前路径
closePath:创建从当前点回到起始点的路径
语法格式:
代码语言:javascript复制<canvas width="1024" height="760" class="canvas">由于您的浏览器版本过低,此图片不能加载</canvas><script>
var ctx = document.querySelector(".canvas").getContext("2d|3d");
ctx.beginPath();
ctx.moveTo(100,100);
ctx.lineTo(700,700);
ctx.lineTo(100,700);
ctx.lineTo(100,100);
ctx.lineWidth = 5;
ctx.strokeStyle = "green";
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.lineCap = "round" //butt(default) round圆头 square方头
//lineCap 有时可以填补连接处的空缺
ctx.moveTo(200,200);
ctx.lineTo(400,400);
ctx.lineTo(200,400);
ctx.lineTo(200,200);
ctx.lineWidth = 5;
ctx.strokeStyle = "yellow";
ctx.stroke();
ctx.closePath();
</script>
===============================================================
ctx.lineWidth = 15;
DrawStart(ctx, 100, 20, 400, 400, -30);
ctx.lineJoin = "miter"; //可以设置的样式有:miter(default)、 bevel斜接、 round圆角
ctx.miterLimit = 7; //如果斜接长度超过 miterLimit 的值,边角会以 lineJoin 的 "bevel" 类型来显示。,这里等于7时,边角会以lineJoin的bevel显示,等于8时则会以miter显示
//斜接长度指的是在两条线交汇处内角和外角之间的距离。
ctx.stroke();
function DrawStart(context, R, r, x, y, rotate) {
//绘画对象 大圆的半径 小圆半径 x轴 y轴
ctx.beginPath();
for (var i = 0; i < 5; i ) {
ctx.lineTo(
Math.cos(((18 72 * i - rotate) / 180) * Math.PI) * R x,
-Math.sin(((18 72 * i - rotate) / 180) * Math.PI) * R y
);
ctx.lineTo(
Math.cos(((54 72 * i - rotate) / 180) * Math.PI) * r x,
-Math.sin(((54 72 * i - rotate) / 180) * Math.PI) * r y
);
}
ctx.closePath();
}
填充
填充函数:
fill :填充当前路径 (注意:如果路径未关闭,那么 fill() 方法会从路径结束点到开始点之间添加一条线,以关闭该路径,然后填充该路径)
填充样式:
fillStyle:填充颜色
语法格式:
代码语言:javascript复制<canvas width="1024" height="760" class="canvas">由于您的浏览器版本过低,此图片不能加载</canvas><script>
var ctx = document.querySelector(".canvas").getContext("2d|3d");
ctx.beginPath();
ctx.moveTo(100,100);
ctx.lineTo(700,700);
ctx.lineTo(100,700);
ctx.lineTo(100,100);
ctx.lineWidth = 5;
ctx.strokeStyle = "green";
ctx.stroke();
ctx.fillStyle = "red";
ctx.fill()
ctx.closePath();
ctx.beginPath();
ctx.moveTo(200,200);
ctx.lineTo(400,400);
ctx.lineTo(200,400);
ctx.lineTo(200,200);
ctx.lineWidth = 5;
ctx.strokeStyle = "yellow";
ctx.stroke();
ctx.closePath();
</script>
案例:四个正方形组成的大方形
代码语言:javascript复制 var ctx = document.querySelector(".canvas").getContext("2d");
let box = [
{p:[{x:0,y:0},{x:512,y:0},{x:512,y:380},{x:0,y:380},{x:0,y:0}],color:"red"},
{p:[{x:512,y:0},{x:1024,y:0},{x:1024,y:380},{x:512,y:380},{x:512,y:0}],color:"green"},
{p:[{x:0,y:380},{x:512,y:380},{x:512,y:760},{x:0,y:760},{x:0,y:380}],color:"blue"},
{p:[{x:512,y:380},{x:1024,y:380},{x:1024,y:760},{x:512,y:760},{x:512,y:380}],color:"yellow"},
]
for(let i=0;i<box.length;i )
{
draw(box[i],ctx);
}
function draw(p,c)
{
c.beginPath();
c.moveTo(p.p[0].x,p.p[0].y);
for(let i=1;i<p.p.length;i )
{
c.lineTo(p.p[i].x,p.p[i].y);
}
c.lineWidth = 5;
c.strokeStyle = p.color;
c.fillStyle = p.color;
c.stroke();
c.fill();
c.closePath();
}
注意点:
- closePath可以解决闭合图形的空隙问题,也有自动闭合的作用。
- 当边框或者填充被遮挡掉的时候,这时可以先填充在画边框,或者先画边框再画线
- 后绘制的图形会顶替掉前面的图形
圆
画圆的函数:
arc(x,y,r,start,end,true|false):画圆弧
arcTo(x1,y1,x2,y2,r):绘制圆弧
语法格式:
代码语言:javascript复制 var ctx = document.querySelector(".canvas").getContext("2d");
var i = 0;
setInterval(() => {
i ;
ctx.fillStyle = "yellow";
ctx.strokeStyle = "red";
ctx.beginPath();
ctx.arc(512, 380, 100, 0, Math.PI * 2 - (Math.PI * 2 * i / 30), true);
// x y 半径 开始位置 结束位置 是否逆时针旋转
ctx.lineWidth = 10;
ctx.stroke();
ctx.fill();
}, 1);
//顺时针:Math.PI * 2 * i / 30
//逆时针:Math.PI * 2 - (Math.PI * 2 * i / 30)
//使用arcTo绘圆角矩形
var ctx = document.querySelector("canvas").getContext("2d");
// ctx.translate(200,200)
// ctx.beginPath();
// ctx.moveTo(100,0);
// ctx.arcTo(400,0,400,800,100);
// ctx.lineTo(400,400);
// ctx.arcTo(400,500,350,500,100);
// ctx.lineTo(100,500);
// ctx.arcTo(0,500,0,450,100);
// ctx.lineTo(0,100);
// ctx.arcTo(0,0,100,0,100)
// ctx.closePath();
function RoundRect(ctx, width, height, r)
{
ctx.beginPath();
ctx.moveTo(r, 0);
ctx.arcTo(width, 0, width, height - r, r);
ctx.lineTo(width, height);
ctx.arcTo(width, height r, width - 50, height r, r);
ctx.lineTo(r, height r);
ctx.arcTo(0, height r, 0, height - 50, r);
ctx.lineTo(0, r);
ctx.arcTo(0, 0, r, 0, r);
ctx.closePath();
}
RoundRect(ctx, 200, 100, 10);
ctx.stroke();
矩形
矩形函数:
reac:绘制矩形附带填充和边框
fillRect:绘制只填充的矩形
strokeRect:绘制只带边框的矩形
语法格式:
代码语言:javascript复制// 参数: x , y , width , height
var ctx = document.querySelector(".canvas").getContext("2d");
ctx.fillStyle = "red";
ctx.strokeStyle = "yellow";
ctx.lineWidth = 5;
var x = 0;
ctx.beginPath();
ctx.rect(100, 100, 300, 300);
ctx.stroke();
ctx.fill();
ctx.beginPath();
ctx.fillStyle = "rgba(0,255,155,0.5)";
ctx.strokeStyle = "yellow";
ctx.fillRect(150, 150, 300, 300);
ctx.strokeRect(100, 100, 400, 400);
案例:绘制五角星
代码语言:javascript复制<!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 width="800" height="800"></canvas>
<script>
var ctx = document.querySelector("canvas").getContext("2d");
ctx.lineWidth = 10;
ctx.beginPath();
for (var i = 0; i <= 5; i ) {
ctx.lineTo(
Math.cos(((18 72 * i) / 180) * Math.PI) * 100 200,
//步骤:先求出角度在转弧度
//cos(18deg)*R sin(18deg)*R
//角度转弧度公式:角度/180*r
//由于数学中的坐标系与canvas的坐标不同所以y轴要为负
-Math.sin(((18 72 * i) / 180) * Math.PI) * 100 200
);
ctx.lineTo(
Math.cos(((54 72 * i) / 180) * Math.PI) * 50 200,
-Math.sin(((54 72 * i) / 180) * Math.PI) * 50 200
);
}
ctx.closePath();
ctx.stroke();
=================================================================================
//五角星封装函数
DrawStart(ctx, 200, 100, 400, 400 , 30);
ctx.stroke();
function DrawStart(context, R, r, x, y,rotate) {
//绘画对象 大圆的半径 小圆半径 x轴 y轴 旋转角度
ctx.beginPath();
for (var i = 0; i < 5; i ) {
ctx.lineTo(
Math.cos(((18 72 * i -rotate) / 180) * Math.PI) * R x,
-Math.sin(((18 72 * i -rotate) / 180) * Math.PI) * R y
);
ctx.lineTo(
Math.cos(((54 72 * i -rotate) / 180) * Math.PI) * r x,
-Math.sin(((54 72 * i -rotate) / 180) * Math.PI) * r y
);
}
ctx.closePath();
}
</script>
</body>
</html>
参考链接:https://www.baidu.com/link?url=3j7UmP9XbkLh0ww6tMOChL_7CATbIoQ15GBatuaJdx2_yCn-jcdshTRF9-l6kMmbONf5cgLEviZEpV4QhjLf2q&wd=&eqid=e9fcd7b0000436fd000000065d2e7488
随机不重复、不切边五角星
代码语言:javascript复制<!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 width="800" height="800" class="canvas"></canvas>
<script src="../node/jquery.js"></script>
<script>
var ctx = document.querySelector("canvas").getContext("2d");
ctx.fillStyle = "black";
ctx.fillRect(
0,
0,
document.querySelector("canvas").width,
document.querySelector("canvas").height
);
ctx.fillStyle = "#fc1";
ctx.strokeStyle = "#fb5";
ctx.lineWidth = 5;
ctx.lineJoin = "round";
var ele = [];
start(ele);
end(ele);
function start(arr) {
for (var i = 0; i < 200; i ) {
var flag = true,
ran = Math.random() * 10 10,
x =
Math.random() *
(document.querySelector("canvas").width - ran * 2)
ran,
y =
Math.random() *
(document.querySelector("canvas").height - ran * 2)
ran,
rotate = Math.random() * 360;
for (var j = 0; j < ele.length; j ) {
var oldx = Math.pow(x - arr[j][1], 2);
var oldy = Math.pow(y - arr[j][2], 2);
var oldr = Math.pow(ran arr[j][0], 2);
if (oldx oldy < oldr) {
flag = false;
}
}
flag ? arr.push([ran, x, y, rotate]) : i--;
}
}
function end(arr) {
for (var i = 0; i < arr.length; i ) {
DrawStart(
ctx,
arr[i][0],
arr[i][0] / 2,
arr[i][1],
arr[i][2],
arr[i][3]
);
ctx.fill();
ctx.stroke();
}
}
function DrawStart(context, R, r, x, y, rotate) {
//绘画对象 大圆的半径 小圆半径 x轴 y轴
ctx.beginPath();
for (var i = 0; i < 5; i ) {
ctx.lineTo(
Math.cos(((18 72 * i - rotate) / 180) * Math.PI) * R x,
-Math.sin(((18 72 * i - rotate) / 180) * Math.PI) * R y
);
ctx.lineTo(
Math.cos(((54 72 * i - rotate) / 180) * Math.PI) * r x,
-Math.sin(((54 72 * i - rotate) / 180) * Math.PI) * r y
);
}
ctx.closePath();
}
</script>
</body>
</html>
绘画状态保存与还原
状态的保存与还原可以使操作更加简便,快速,主要作用于将绘画的状态来回快速切换,状态保存,可以保存如:线条的样式、颜色、填充、图形变换等,特别是配合图形变换,两者可以互补长短
状态保存和还原的对应函数:
save:保存当前的状态,以便restore还原
restore:还原到之前sava保存的状态
语法格式:
代码语言:javascript复制//这里配合图形变换来演示
//图形变换系列的函数,重复使用是叠加效果,而不是替换,所以使用图形变换 状态保存还原可以更快速简便
//正常方式
var ctx = document.querySelector(".canvas").getContext("2d");
ctx.beginPath();
ctx.fillStyle = "red";
ctx.translate(100, 100);
ctx.fillRect(0, 0, 400, 400);
ctx.translate(-100, -100);
ctx.fillStyle = "red";
ctx.fillRect(400, 400, 400, 400);
ctx.closePath();
//图形变换函数连续使用会进行叠加效果,会影响到下面绘制的图形,为了不影响,必须再次使用变换函数来还原
//这里运用了canvas的状态保存还原后,可以更方便使用变换函数
var ctx = document.querySelector(".canvas").getContext("2d");
ctx.beginPath();
ctx.fillStyle = "red";
ctx.save();
ctx.translate(100, 100);
ctx.fillRect(0, 0, 400, 400);
ctx.restore();
ctx.fillRect(400, 400, 400, 400);
ctx.closePath();
图形变换
图形变换系列函数:
translate(x,y):偏移、移动
rotate(?deg):旋转
scale(sx,sy):缩放
变换矩阵:
transform(a,b,c,d,e,f):图形变换矩阵函数是一个把所有变换效果结于一身的函数,连续使用会造成链集和叠加效果
setTransform(a,b,c,d,e,f):可以重置transform函数,使之前的失效
语法格式:
代码语言:javascript复制//改用图形变换函数 translate rotate scale 后的无重复五角星
//scale 会有许多副作用如:边框将会变大、长宽比也好增大、x、y也会随之增大
<!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 width="800" height="800" class="canvas"></canvas>
<script src="../node/jquery.js"></script>
<script>
var ctx = document.querySelector("canvas").getContext("2d");
ctx.fillStyle = "black";
ctx.fillRect(
0,
0,
document.querySelector("canvas").width,
document.querySelector("canvas").height
);
ctx.fillStyle = "#fc1";
ctx.strokeStyle = "#fb5";
ctx.lineWidth = 5;
ctx.lineJoin = "round";
var ele = [];
start(ele);
end(ele);
function start(arr) {
for (var i = 0; i < 200; i ) {
var flag = true,
ran = Math.random() * 10 10,
x =
Math.random() *
(document.querySelector("canvas").width - ran * 2)
ran,
y =
Math.random() *
(document.querySelector("canvas").height - ran * 2)
ran,
rotate = Math.random() * 360;
for (var j = 0; j < ele.length; j ) {
var oldx = Math.pow(x - arr[j][1], 2);
var oldy = Math.pow(y - arr[j][2], 2);
var oldr = Math.pow(ran arr[j][0], 2);
if (oldx oldy < oldr) {
flag = false;
}
}
flag ? arr.push([ran, x, y, rotate]) : i--;
}
}
function end(arr) {
for (var i = 0; i < arr.length; i ) {
ctx.save();
ctx.beginPath();
ctx.translate(arr[i][1], arr[i][2]);
ctx.rotate(arr[i][3]);
ctx.scale(0.5,0.5)
DrawStart(ctx, arr[i][0]);
ctx.fill();
ctx.stroke();
ctx.closePath();
ctx.restore();
}
}
function DrawStart(context, r) {
//绘画对象 大圆的半径 小圆半径 x轴 y轴
for (var i = 0; i <= 5; i ) {
ctx.lineTo(
Math.cos(((18 72 * i) / 180) * Math.PI) * r,
-Math.sin(((18 72 * i) / 180) * Math.PI) * r
);
ctx.lineTo(
(Math.cos(((54 72 * i) / 180) * Math.PI) * r) / 2,
(-Math.sin(((54 72 * i) / 180) * Math.PI) * r) / 2
);
}
}
</script>
</body>
</html>
//transform
var ctx = document.querySelector(".canvas").getContext("2d");
ctx.beginPath();
ctx.fillStyle = "red";
ctx.save();
ctx.transform(1.5,0,0,1.5,200,100);
a:水平缩放 b:水平倾斜 c:垂直倾斜 d:垂直缩放 e:水平位移 f:垂直位移
ctx.fillRect(0, 0, 400, 400);
ctx.restore();
ctx.fillRect(400, 400, 400, 400);
ctx.closePath();
渐变
渐变系列函数:
createLinearGradient(x,y,EndX,EndY):创建渐变
addColorStop(0-1,color) :添加颜色
createRadialGradient(x1,y1,r1,x2,y2,r2):创建一个径向的渐变,整个径向渐变发生在俩个圆中间
语法格式:
代码语言:javascript复制var ctx = document.querySelector("canvas").getContext("2d");
document.querySelector("canvas").width = document.body.clientWidth;
document.querySelector("canvas").height = document.body.clientHeight;
//创建渐变对象
var grd = ctx.createLinearGradient(
0, //x
0, //y
0, //endX
document.querySelector("canvas").height //endY
//这里的渐变方向是从上往下
);
//下面的是径向渐变,在定义的两个圆之间产生渐变
//第一个圆是外圆,内圆则是第二个
//var grd = ctx.createRadialGradient(document.querySelector("canvas").width/2,document.querySelector("canvas").height/2,400,document.querySelector("canvas").width/2,document.querySelector("canvas").height/2,0)
//添加颜色,取值范围(0,1),必须有起点,终点
grd.addColorStop(0, "black");
grd.addColorStop(1, "#035");
//最后把渐变对象添加到要应用的样式填充上
ctx.fillStyle = grd;
ctx.fillRect(
0,
0,
document.querySelector("canvas").width,
document.querySelector("canvas").height
);
三角函数讲解
绘制圆形
1角度 = 1* Math.PI/ 180弧度
1弧度 = 1* 180 / Math.PI 角度
arc(x,y,r,0,360,false)
x,y 圆心坐标位置
r 圆半径
0,360
从0度到360度所对应的弧度 (弧度: 角度值*Math.PI/180) true/false 逆时针/顺时针绘图
添加图片、视频、canvas
相关函数:
createPattern(ele,repeat|repeat-x|repeat-y|no-repeat):添加图片、视频、画布到指定的场景
语法格式:
代码语言:javascript复制//添加图片
var ctx = document.querySelector("canvas").getContext("2d");
var img = new Image();
img.src = "../newIMg.png";
img.onload = () => {
var createImg = ctx.createPattern(img, "repeat");
ctx.fillStyle = createImg;
ctx.fillRect(0, 0, 800, 800);
};
//添加图片时注意:必须图片加载完后在载入createPattern,否则载入失败
//添加画布
function createImgCanvas() {
var c = document.createElement("canvas");
var ctx = c.getContext("2d");
c.width = 400;
c.height = 400;
ctx.fillStyle = "yellow";
ctx.transform(1, 0, 0, 1, c.width / 2, c.height / 2);
DrawStart(ctx, 200);
ctx.fill();
return c;
}
var ctx = document.querySelector("canvas").getContext("2d");
document.querySelector("canvas").width = 1400;
document.querySelector("canvas").height = 1400;
ctx.fillStyle = ctx.createPattern(createImgCanvas(), "repeat");
ctx.fillRect(0, 0, 1400, 1400);
案例:绘制圆角矩形
代码语言:javascript复制 /*
把圆分为4份,顺时针顺序绘制
Math.PI / 2 半圆分1为2
Math.PI 一个圆中的一半
Math.PI*3/2 || Math.PI*1.5 1个半圆加一个1分为2的半圆
Math.PI*2 完整的圆
*/
var ctx = document.querySelector("canvas").getContext("2d");
ctx.beginPath();
ctx.arc(400 - 50, 400 - 50, 50, 0, Math.PI / 2);
ctx.lineTo(50, 400);
ctx.arc(50, 400 - 50, 50, Math.PI / 2, Math.PI);
ctx.lineTo(0, 50);
ctx.arc(50, 50, 50, Math.PI, (Math.PI * 3) / 2);
ctx.lineTo(400 - 50, 0);
ctx.arc(400 - 50, 50, 50, (Math.PI * 3) / 2, Math.PI * 2);
ctx.closePath();
ctx.stroke();
//封装函数
function PathRoundRect(ctx, width, height, r)
{
ctx.beginPath();
ctx.arc(width - r, height - r, r, 0, Math.PI / 2);
ctx.lineTo(r, height);
ctx.arc(r, height - r, r, Math.PI / 2, Math.PI);
ctx.lineTo(0, r);
ctx.arc(r, r, r, Math.PI, Math.PI * 1.5);
ctx.lineTo(width - r, 0);
ctx.arc(width - r, r, r, (Math.PI * 3) / 2, Math.PI * 2);
ctx.closePath();
}
//升级版
function PathRoundRect(ctx, width, height, r,optionColor,optionStyle)
{
if(r*2>width||r*2>height)return;
if(optionStyle)
{
optionStyle.stroke === true ? (optionColor.stroke ? (ctx.strokeStyle =optionColor.stroke ):null) : null;
optionStyle.fill === true ?(optionColor.fill ? (ctx.fillStyle =optionColor.fill):null) : null;
}
ctx.beginPath();
ctx.arc(width - r, height - r, r, 0, Math.PI / 2);
ctx.lineTo(r, height);
ctx.arc(r, height - r, r, Math.PI / 2, Math.PI);
ctx.lineTo(0, r);
ctx.arc(r, r, r, Math.PI, Math.PI * 1.5);
ctx.lineTo(width - r, 0);
ctx.arc(width - r, r, r, (Math.PI * 3) / 2, Math.PI * 2);
ctx.closePath();
}
//最终版
function RoundRect(ctx, width, height, r, optionColor, optionStyle) {
var flagfill,flagstroke;
if (r*2 > width || r*2 > height) return;
if (optionStyle) {
optionStyle.stroke === true
? optionColor.stroke
? (ctx.strokeStyle = optionColor.stroke)
: null
: null;
optionStyle.fill === true
? optionColor.fill
? (ctx.fillStyle = optionColor.fill)
: null
: null;
flagfill = optionColor.fill ?true:false;
flagstroke = optionColor.stroke ?true:false;
}
ctx.beginPath();
ctx.arc(width - r, height - r, r, 0, Math.PI / 2);
ctx.lineTo(r, height);
ctx.arc(r, height - r, r, Math.PI / 2, Math.PI);
ctx.lineTo(0, r);
ctx.arc(r, r, r, Math.PI, Math.PI * 1.5);
ctx.lineTo(width - r, 0);
ctx.arc(width - r, r, r, (Math.PI * 3) / 2, Math.PI * 2);
ctx.closePath();
flagstroke ? ctx.stroke() : null;
flagfill ? ctx.fill() : null;
}
案例:2048九宫格
代码语言:javascript复制 var ctx = document.querySelector("canvas").getContext("2d");
ctx.translate(800/4,800/4)
RoundRect(
ctx,
480,
470,
10,
{ fill: "red", stroke: "green" },
{ fill: true, stroke: true }
);
for (var i = 0; i < 4; i ) {
ctx.save();
ctx.translate(10, i * 15);
for (var j = 0; j < 4; j ) {
ctx.save();
ctx.translate(j * 120, i * 100 15);
RoundRect(
ctx,
100,
100,
10,
{ fill: "green", stroke: "green" },
{ fill: true, stroke: true }
);
ctx.restore();
}
ctx.restore();
}
function RoundRect(ctx, width, height, r, optionColor, optionStyle) {
var flagfill, flagstroke;
if (r > width || r > height) return;
if (optionStyle) {
optionStyle.stroke === true
? optionColor.stroke
? (ctx.strokeStyle = optionColor.stroke)
: null
: null;
optionStyle.fill === true
? optionColor.fill
? (ctx.fillStyle = optionColor.fill)
: null
: null;
flagfill = optionColor.fill ? true : false;
flagstroke = optionColor.stroke ? true : false;
}
ctx.beginPath();
ctx.arc(width - r, height - r, r, 0, Math.PI / 2);
ctx.lineTo(r, height);
ctx.arc(r, height - r, r, Math.PI / 2, Math.PI);
ctx.lineTo(0, r);
ctx.arc(r, r, r, Math.PI, Math.PI * 1.5);
ctx.lineTo(width - r, 0);
ctx.arc(width - r, r, r, (Math.PI * 3) / 2, Math.PI * 2);
ctx.closePath();
flagstroke ? ctx.stroke() : null;
flagfill ? ctx.fill() : null;
}
案例:绘制弯月
代码语言:javascript复制 pathMoon(ctx, 2, 300, 300, 200);
function pathMoon(ctx, d, x, y, r, deg, color) {
ctx.save();
ctx.translate(x, y);
ctx.scale(r, r);
ctx.rotate(deg || 0);
ctx.beginPath();
Moon(d, ctx);
ctx.fillStyle = color ? color : "yellow";
ctx.fill();
ctx.closePath();
ctx.restore();
function Moon(d, ctx) {
ctx.arc(0, 0, 1, Math.PI * 0.5, Math.PI * 1.5, true);
ctx.moveTo(0, -1);
ctx.arcTo(d, 0, 0, 1, dis(0, -1, d, 0) / d);
}
function dis(x1, y1, x2, y2) {
return Math.sqrt((x1 - x2) * (x1 - x2) (y1 - y2) * (y1 - y2));
}
}
贝塞尔曲线
贝塞尔曲线相关函数:
quadraticCurveTo(x1,y1,x2,y2):二次贝塞尔曲线 一个控制点 1
bezierCurveTo(x1,y1,x2,y2,x3,y3):三次贝塞尔曲线 两个控制点 1 2
代码语言:javascript复制//起始点不由函数来定,可以用moveTo等画路径的函数来定
//二次贝塞尔曲线
ctx.moveTo(0, 0);
ctx.quadraticCurveTo(800,400,400,800)
ctx.stroke()
<!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>
<style>
html,
body {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<canvas class="canvas"></canvas>
<script src="../node/jquery.js"></script>
<script>
var ctx = document.querySelector("canvas").getContext("2d");
document.querySelector("canvas").width = document.body.clientWidth;
document.querySelector("canvas").height = document.body.clientHeight;
ctx.save();
var grd = ctx.createLinearGradient(0,0,0,document.querySelector("canvas").height);
grd.addColorStop(0,"black");
grd.addColorStop(1,"#035");
ctx.fillStyle = grd;
ctx.fillRect(0,0,document.querySelector("canvas").width,document.querySelector("canvas").height);
ctx.restore();
ctx.fillStyle = "#fc1";
ctx.strokeStyle = "#fb5";
ctx.lineWidth = 5;
ctx.lineJoin = "round";
var ele = [];
start(ele,200);
end(ele);
pathMoon(ctx, 2, document.querySelector("canvas").width*0.85, document.querySelector("canvas").height/4,80,0,"#fc1");
RectLoda(ctx);
function RectLoda(ctx)
{
ctx.save();
ctx.beginPath();
ctx.moveTo(0,document.querySelector("canvas").height*0.65);
//三次贝塞尔曲线应用 ctx.bezierCurveTo(document.querySelector("canvas").width/2,650,document.querySelector("canvas").width/2,document.querySelector("canvas").height/3,document.querySelector("canvas").width,document.querySelector("canvas").height-200);
ctx.lineTo(document.querySelector("canvas").width,document.querySelector("canvas").height)
ctx.lineTo(0,document.querySelector("canvas").height)
var bgcolor = ctx.createLinearGradient(0,document.querySelector("canvas").height,0,0);
bgcolor.addColorStop(0,"#030");
bgcolor.addColorStop(1,"#580");
ctx.fillStyle = bgcolor;
ctx.fill();
ctx.closePath();
ctx.restore();
}
function pathMoon(ctx, d, x, y, r, deg, color) {
ctx.save();
ctx.translate(x, y);
ctx.scale(r, r);
ctx.rotate(deg || 0);
ctx.beginPath();
Moon(d, ctx);
ctx.fillStyle = color ? color : "yellow";
ctx.fill();
ctx.closePath();
ctx.restore();
function Moon(d, ctx) {
ctx.arc(0, 0, 1, Math.PI * 0.5, Math.PI * 1.5, true);
ctx.moveTo(0, -1);
ctx.arcTo(d, 0, 0, 1, dis(0, -1, d, 0) / d);
}
function dis(x1, y1, x2, y2) {
return Math.sqrt((x1 - x2) * (x1 - x2) (y1 - y2) * (y1 - y2));
}
}
function start(arr,num) {
for (var i = 0; i < num; i ) {
var flag = true,
ran = Math.random() * 10 5,
x =
Math.random() *
(document.querySelector("canvas").width - ran * 2)
ran,
y =
(Math.random() *
(document.querySelector("canvas").height - ran * 2)
ran) *
0.65,
rotate = Math.random() * 360;
for (var j = 0; j < ele.length; j ) {
var oldx = Math.pow(x - arr[j][1], 2);
var oldy = Math.pow(y - arr[j][2], 2);
var oldr = Math.pow(ran arr[j][0], 2);
if (oldx oldy < oldr) {
flag = false;
}
if(x>document.querySelector("canvas").width*0.85&&x<document.querySelector("canvas").width*0.85 80*1.15)
{
flag = false;
}
}
flag ? arr.push([ran, x, y, rotate]) : i--;
}
}
function end(arr) {
for (var i = 0; i < arr.length; i ) {
ctx.save();
ctx.beginPath();
ctx.translate(arr[i][1], arr[i][2]);
ctx.rotate(arr[i][3]);
ctx.scale(0.7, 0.7);
DrawStart(ctx, arr[i][0]);
ctx.fill();
ctx.stroke();
ctx.closePath();
ctx.restore();
}
}
function DrawStart(ctx, r) {
//绘画对象 大圆的半径 小圆半径 x轴 y轴
for (var i = 0; i <= 5; i ) {
ctx.lineTo(
Math.cos(((18 72 * i) / 180) * Math.PI) * r,
-Math.sin(((18 72 * i) / 180) * Math.PI) * r
);
ctx.lineTo(
(Math.cos(((54 72 * i) / 180) * Math.PI) * r) / 2,
(-Math.sin(((54 72 * i) / 180) * Math.PI) * r) / 2
);
}
}
</script>
</body>
</html>
字体
字体绘制相关函数:
font:设置字体样式属性 五个参数依次是font-style(italic oblique)、font-variant(small-caps)、font-weight(bold lighter bolder)、font-size、font-family
fillText(string,x,y,length):绘制带填充字体
strokeText(string,x,y,length):绘制带边框的字体
textAlign:设置字体水平对齐 参数有:right center left
textBaseline:设置字体垂直对齐 参数有:top middle bottom alphabetic(defalut) ideographic hanging
measureText(String).width:获取文本宽度(会根据font设置的字体、字号来决定)
语法格式:
代码语言:javascript复制 var ctx = document.querySelector(".canvas").getContext("2d");
var grd = ctx.createLinearGradient(0,0,800,0);
grd.addColorStop(0,"red");
grd.addColorStop(0.5,"yellow");
grd.addColorStop(1,"green");
ctx.fillStyle = grd;
ctx.font = "bold 40px 微软雅黑 ";
ctx.fillText("How are you!",100,100,300);
//字体可以填充渐变色、图形纹理、另一个画布
===================================================================
//只带边框的字体
var ctx = document.querySelector(".canvas").getContext("2d");
var grd = ctx.createLinearGradient(0,0,800,0);
grd.addColorStop(0,"red");
grd.addColorStop(0.5,"yellow");
grd.addColorStop(1,"green");
ctx.lineWidth =2;
ctx.strokeStyle = grd;
ctx.font = "bold 40px 微软雅黑 ";
ctx.strokeText("How are you!",100,100,300);
===============================================
//带纹理的字体
var ctx = document.querySelector(".canvas").getContext("2d");
// var grd = ctx.createLinearGradient(0,0,800,0);
// grd.addColorStop(0,"red");
// grd.addColorStop(0.5,"yellow");
// grd.addColorStop(1,"green");
var img = new Image();
img.src = "../newIMg.png";
img.onload = function() {
var pattern = ctx.createPattern(img, "repeat");
ctx.fillStyle = pattern;
ctx.strokeStyle = "red";
ctx.lineWidth =1;
ctx.font = "bold 40px 微软雅黑 ";
ctx.strokeText("How are you!", 100, 100, 300);
ctx.fillText("How are you!", 100, 100, 300);
};
水平对齐效果:
垂直对齐效果:
案例:水平垂直居中
代码语言:javascript复制 var ctx = document.querySelector(".canvas").getContext("2d");
ctx.fillStyle = "red";
ctx.strokeStyle = "red";
ctx.moveTo(400, 0);
ctx.lineTo(400, 800);
ctx.moveTo(0, 400);
ctx.lineTo(800, 400);
ctx.stroke();
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.font = "bold 100px 微软雅黑 ";
ctx.strokeText("How are you!", 400, 400);
阴影
阴影相关属性:
shadowColor:设置阴影颜色
shadowOffsetX:设置阴影X偏移
shadowOffsetY:设置阴影Y偏移
shadowBlur:设置阴影模糊扩散程度
语法格式:
代码语言:javascript复制 var ctx = document.querySelector("canvas").getContext("2d");
ctx.shadowColor = "black";
ctx.fillStyle = "red"
var num = 0;
var flag = true;
setInterval(function() {
ctx.shadowOffsetX = -20 num;
ctx.shadowOffsetY = -20 num;
num == 100 ? (flag = false) : num == 0 ? (flag = true) : null;
flag ? num : num--;
ctx.shadowBlur = num;
ctx.clearRect(0, 0, 800, 800);
ctx.fillRect(100, 100, 400, 400);
}, 50);
透明
透明相关函数:
在canvas中要实现透明,可以使用rgba颜色,也可以使用以下方法
globalAlpha:设置透明度 范围(1-0) 全局透明
语法格式:
代码语言:javascript复制 var ctx = document.querySelector("canvas").getContext("2d");
var color = ["red","green","yellow","blue","black"]
for(var i=0;i<200;i )
{
var randomX = Math.random()*800;
var randomY = Math.random()*800;
var randomR = Math.random()*30;
var R = Math.floor(Math.random()*255),G = Math.floor(Math.random()*255),B = Math.floor(Math.random()*255);
ctx.save();
ctx.beginPath();
ctx.globalAlpha = 0.7;
ctx.fillStyle = `rgb(${R},${G},${B})`;
ctx.arc(randomX,randomY,randomR,0,Math.PI*2);
ctx.fill();
ctx.closePath();
ctx.restore();
}
遮盖顺序
xx.globalCompositeOperation = “source-over” (默认,后绘制的图形会压在先绘制的图形上) / “destination-over”(先绘制的图形压在后绘制的图形上)
相关属性:
globalCompositeOperation :改变元素显示效果与遮盖顺序
各个参数的实现效果可以参考菜鸟,或有canvas手册的网址,或以下链接
https://blog.csdn.net/fe_dev/article/details/81985367
此链接,有水滴扩散、刮刮卡案例参考
参数:
语法格式:
代码语言:javascript复制<!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>
<style>
html,
body {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<canvas class="canvas" width="800" height="800"></canvas>
<script src="../node/jquery.js"></script>
<script>
var ctx = document.querySelector("canvas").getContext("2d");
var color = ["red","green","yellow","blue","black"]
var Balls = [];
for(var i=0;i<200;i )
{
var randomR = Math.random()*30 10;
var randomX = Math.random()*(800-randomR*2) randomR;
var randomY = Math.random()*(800-randomR*2) randomR;
var R = Math.floor(Math.random()*255),G = Math.floor(Math.random()*255),B = Math.floor(Math.random()*255);
let balls ={
x:randomX,
y:randomY,
r:randomR,
color:`rgb(${R},${G},${B})`,
vx:(Math.random()*5 5)*(Math.pow(-1,Math.floor(Math.random()*100))),
vy:(Math.random()*5 5)*(Math.pow(-1,Math.floor(Math.random()*100))),
}
Balls.push(balls);
}
setInterval(()=>{
draw(ctx)
},50)
function draw(ctx)
{
ctx.clearRect(0,0,800,800)
for(let i=0;i<Balls.length;i )
{
ctx.save();
ctx.beginPath();
ctx.globalCompositeOperation = "xor";
ctx.fillStyle = Balls[i].color;
ctx.arc(Balls[i].x,Balls[i].y,Balls[i].r,0,Math.PI*2);
ctx.fill();
ctx.closePath();
ctx.restore();
Balls[i].x =Balls[i].vx;
Balls[i].y =Balls[i].vy;
if(Balls[i].x-Balls[i].r<=0)
{
Balls[i].vx = -Balls[i].vx;
Balls[i].x = Balls[i].r;
}
if(Balls[i].x Balls[i].r >= 800)
{
Balls[i].vx = -Balls[i].vx;
Balls[i].x = 800-Balls[i].r;
}
if(Balls[i].y-Balls[i].r<=0)
{
Balls[i].vy = -Balls[i].vy;
Balls[i].y = Balls[i].r;
}
if(Balls[i].y Balls[i].r>=800)
{
Balls[i].vy = -Balls[i].vy;
Balls[i].y = 800-Balls[i].r;
}
}
}
</script>
</body>
</html>
剪切
相关函数:
clip:相对于上个填充路径做剪切效果
语法格式:
代码语言:javascript复制<!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>
<style>
html,
body {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<canvas class="canvas" width="800" height="800"></canvas>
<script src="../node/jquery.js"></script>
<script>
var ctx = document.querySelector("canvas").getContext("2d");
var r = 150;
ctx.fillStyle = "black";
ctx.fillRect(0, 0, 800, 800);
ctx.canvas.onmousemove = e => {
ctx.clearRect(0, 0, 800, 800);
ctx.beginPath();
ctx.fillStyle = "black";
ctx.fillRect(0, 0, 800, 800);
ctx.closePath();
ctx.save();
ctx.beginPath();
ctx.fillStyle = "rgba(255,255,255,1)";
var x = e.pageX - r <= 0 ? r : e.pageX;
var y = e.pageY - r <= 0 ? r : e.pageY;
x = e.pageX r > 800 ? 800 - r : x;
y = e.pageY r > 800 ? 800 - r : y;
ctx.arc(x, y, r, 0, Math.PI * 2);
ctx.fill();
ctx.clip();
ctx.closePath();
ctx.beginPath();
ctx.fillStyle = "red";
ctx.font = "200px bold 微软雅黑";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText("Canvas", 400, 400);
ctx.closePath();
ctx.restore();
document.onkeyup = ev => {
ev.keyCode === 38 ? (r = 20) : null;
ev.keyCode === 40 ? (r -= 20) : null;
if (r >= 390) r = 390;
ctx.canvas.onmousemove(e);
return false;
};
};
ctx.canvas.onmouseout = () => {
ctx.fillStyle = "black";
ctx.fillRect(0, 0, 800, 800);
document.onkeyup = null;
};
</script>
</body>
</html>
实现剪纸效果
剪纸效果参考非零环绕原侧,自动识别里、外、面,一个面不同时出现顺时针和逆时针就填充,如果同时出现顺时针和逆时针就不填充,这也就说明了图形的绘制方向,会影响其是否填充
语法格式:
代码语言:javascript复制<!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>
<style>
html,
body {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<canvas class="canvas" width="800" height="800"></canvas>
<script src="../node/jquery.js"></script>
<script>
var ctx = document.querySelector("canvas").getContext("2d");
ctx.beginPath();
ctx.rect(200, 200, 400, 200);
drawRect(ctx, 220, 220, 100, 100);
ctx.arc(400, 270, 50, Math.PI * 2, 0, true);
Triangle(ctx, 510, 220, 460, 320, 560, 320);
ctx.closePath();
ctx.fillStyle = "red";
ctx.shadowColor = "black";
ctx.shadowOffsetX = 10;
ctx.shadowOffsetY = 10;
ctx.fill();
function drawRect(ctx, x, y, w, h) {
ctx.moveTo(x, y);
ctx.lineTo(x, y h);
ctx.lineTo(x w, y h);
ctx.lineTo(x w, y);
ctx.lineTo(x, y);
}
function Triangle(ctx, x1, y1, x2, y2, x3, y3) {
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.lineTo(x3, y3);
ctx.lineTo(x1, y1);
}
</script>
</body>
</html>
交互
canvas交互相关函数:
isPointInPath(x,y):检测指定的坐标是否在绘制元素内,只能判断最后一个绘制的封闭路径
语法格式:
代码语言:javascript复制//点击填充颜色
<!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>
<style>
* {
padding: 0;
margin: 0;
}
html,
body {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<canvas class="canvas" width="800" height="800"></canvas>
<script src="../node/jquery.js"></script>
<script>
var ctx = document.querySelector("canvas").getContext("2d");
var Balls = [];
for (var i = 0; i < 10; i ) {
ctx.beginPath();
Balls.push({
x: Math.random() * 800,
y: Math.random() * 800,
r: Math.random() * 100
});
}
Draw(ctx);
function Draw(ctx) {
for (let i = 0; i < Balls.length; i ) {
ctx.beginPath();
ctx.arc(Balls[i].x, Balls[i].y, Balls[i].r, 0, Math.PI * 2);
ctx.stroke();
}
ctx.canvas.addEventListener("click", function(event) {
for (let i = 0; i < Balls.length; i ) {
ctx.beginPath();
ctx.arc(Balls[i].x, Balls[i].y, Balls[i].r, 0, Math.PI * 2);
if (ctx.isPointInPath(event.pageX, event.pageY)) {
ctx.fillStyle = "yellow";
ctx.fill();
}
}
});
}
</script>
</body>
</html>
//鼠标滑入填充颜色,滑出清空颜色
<!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>
<style>
* {
padding: 0;
margin: 0;
}
html,
body {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<canvas class="canvas" width="800" height="800"></canvas>
<script src="../node/jquery.js"></script>
<script>
var ctx = document.querySelector("canvas").getContext("2d");
var Balls = [];
for (var i = 0; i < 10; i ) {
ctx.beginPath();
Balls.push({
x: Math.random() * 800,
y: Math.random() * 800,
r: Math.random() * 100
});
}
Draw(ctx);
function Draw(ctx) {
for (let i = 0; i < Balls.length; i ) {
ctx.beginPath();
ctx.arc(Balls[i].x, Balls[i].y, Balls[i].r, 0, Math.PI * 2);
ctx.stroke();
}
ctx.canvas.addEventListener("mousemove", function(event) {
ctx.clearRect(0, 0, 800, 800);
for (let i = 0; i < Balls.length; i ) {
ctx.beginPath();
ctx.arc(Balls[i].x, Balls[i].y, Balls[i].r, 0, Math.PI * 2);
if (ctx.isPointInPath(event.pageX, event.pageY)) {
ctx.fillStyle =
"rgb("
Math.random() * 255
","
Math.random() * 255
","
Math.random() * 255
")";
ctx.fill();
} else ctx.stroke();
}
});
}
</script>
</body>
</html>
案例:小球滚动(面向对象 控制面板)
代码语言:javascript复制<!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>
<style>
html,
body {
width: 100%;
height: 100%;
}
.canvasBox {
width: 800px;
height: 800px;
position: relative;
}
.canvasBox > .SetupPanel {
width: 300px;
height: 200px;
background: #99b4e487;
border-radius: 30px;
position: absolute;
left: 0;
top: 0;
color: white;
}
.canvasBox > .SetupPanel > h1 {
text-align: center;
line-height: 25px;
}
.canvasBox > .SetupPanel > a {
float: left;
color: #478aff87;
background: #e5eeff;
border-radius: 5px;
padding: 10px 0;
margin: 3px 0;
text-decoration: none;
text-align: center;
line-height: 15px;
width: 100%;
}
</style>
</head>
<body>
<div class="canvasBox">
<canvas class="canvas" width="800" height="800"></canvas>
<div class="SetupPanel">
<h1>控制面板</h1>
<a href="javascript:void(0)">点击停止</a>
<a href="javascript:void(0)">点击切换背景颜色</a>
<a href="javascript:void(0)">点击切换覆盖模式</a>
</div>
</div>
<script src="../node/jquery.js"></script>
<script>
class Animate {
constructor(canvas) {
this.canvas = document.querySelector(canvas);
this.ctx = this.canvas.getContext("2d");
this.initAttr();
this.initDraw();
this.initEvent();
}
initAttr() {
this.color = ["red", "green", "yellow", "blue", "black"];
this.bgcolor = null;
this.Balls = [];
this.flag = true;
this.module = ["xor", "lighter", null];
this.option = null;
this.time = null;
}
initEvent() {
document.querySelectorAll(
".canvasBox>.SetupPanel>a"
)[0].onclick = () => {
if (this.flag) {
clearInterval(this.time);
this.flag = false;
document.querySelectorAll(
".canvasBox>.SetupPanel>a"
)[0].innerHTML = "点击开始";
document.querySelectorAll(
".canvasBox>.SetupPanel>a"
)[0].style.background = "red";
} else {
this.time = setInterval(() => {
this.draw(this.bgcolor);
}, 50);
this.flag = true;
document.querySelectorAll(
".canvasBox>.SetupPanel>a"
)[0].innerHTML = "点击停止";
document.querySelectorAll(
".canvasBox>.SetupPanel>a"
)[0].style.background = "";
}
};
document.querySelectorAll(
".canvasBox>.SetupPanel>a"
)[1].onclick = () => {
this.bgcolor = this.color[
parseInt(Math.random() * this.color.length - 1)
];
};
document.querySelectorAll(
".canvasBox>.SetupPanel>a"
)[2].onclick = () => {
this.option = this.module[
Math.ceil(Math.random() * this.module.length - 1)
];
};
}
initDraw() {
for (let i = 0; i < 200; i ) {
let randomR = Math.random() * 30 10;
let randomX = Math.random() * (800 - randomR * 2) randomR;
let randomY = Math.random() * (800 - randomR * 2) randomR;
let R = Math.floor(Math.random() * 255),
G = Math.floor(Math.random() * 255),
B = Math.floor(Math.random() * 255);
let balls = {
x: randomX,
y: randomY,
r: randomR,
color: `rgb(${R},${G},${B})`,
vx:
(Math.random() * 5 5) *
Math.pow(-1, Math.floor(Math.random() * 100)),
vy:
(Math.random() * 5 5) *
Math.pow(-1, Math.floor(Math.random() * 100))
};
this.Balls.push(balls);
}
}
draw(bgcolor) {
this.ctx.clearRect(0, 0, 800, 800);
this.bgDraw(bgcolor);
for (let i = 0; i < this.Balls.length; i ) {
this.ctx.save();
this.ctx.beginPath();
this.ctx.globalCompositeOperation = this.option;
this.ctx.fillStyle = this.Balls[i].color;
this.ctx.arc(
this.Balls[i].x,
this.Balls[i].y,
this.Balls[i].r,
0,
Math.PI * 2
);
this.ctx.fill();
this.ctx.closePath();
this.ctx.restore();
this.Balls[i].x = this.Balls[i].vx;
this.Balls[i].y = this.Balls[i].vy;
if (this.Balls[i].x - this.Balls[i].r <= 0) {
this.Balls[i].vx = -this.Balls[i].vx;
this.Balls[i].x = this.Balls[i].r;
}
if (this.Balls[i].x this.Balls[i].r >= 800) {
this.Balls[i].vx = -this.Balls[i].vx;
this.Balls[i].x = 800 - this.Balls[i].r;
}
if (this.Balls[i].y - this.Balls[i].r <= 0) {
this.Balls[i].vy = -this.Balls[i].vy;
this.Balls[i].y = this.Balls[i].r;
}
if (this.Balls[i].y this.Balls[i].r >= 800) {
this.Balls[i].vy = -this.Balls[i].vy;
this.Balls[i].y = 800 - this.Balls[i].r;
}
}
}
bgDraw(bgcolor) {
this.ctx.beginPath();
this.ctx.fillStyle = bgcolor;
this.ctx.fillRect(0, 0, 800, 800);
this.ctx.closePath();
}
}
//初始化对象
let animate = new Animate("canvas");
var ctx = animate.ctx;
//开始执行动画
animate.time = setInterval(() => {
animate.draw(animate.bgcolor);
}, 50);
</script>
</body>
</html>
清除
清除也称重绘,在动画应用当中是不可分割的,动画是一帧一帧的播放,中间少不了清除的步骤,否则将达不到动画的播放帧数标准
清除画布相关函数:
clearRect(startX,startY,endX,endY):清除参数指定范围内绘制的元素
语法格式:
代码语言:javascript复制ctx.clearRect(0,0,canvas.width,canvas.height);
扩充Canvas 2d方法
在有些时候,我们自定义的函数,不能像canvas自带的函数一样,不用传入绘制上下午对象,而我们自定义的必须把绘制对象传入函数里才可以使用,那么有没有方法可以解决呢,在canvas实例对象的原型上添加方法即可
语法格式:
代码语言:javascript复制<!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>
<style>
html,
body {
width: 100%;
height: 100%;
}
.canvasBox {
width: 800px;
height: 800px;
position: relative;
}
.canvasBox > .SetupPanel {
width: 300px;
height: 200px;
background: #99b4e487;
border-radius: 30px;
position: absolute;
left: 0;
top: 0;
color: white;
}
.canvasBox > .SetupPanel > h1 {
text-align: center;
line-height: 25px;
}
.canvasBox > .SetupPanel > a {
float: left;
color: #478aff87;
background: #e5eeff;
border-radius: 5px;
padding: 10px 0;
margin: 3px 0;
text-decoration: none;
text-align: center;
line-height: 15px;
width: 100%;
}
</style>
</head>
<body>
<div class="canvasBox">
<canvas class="canvas" width="800" height="800"></canvas>
</div>
<script src="../node/jquery.js"></script>
<script>
let ctx = document.querySelector(".canvas").getContext("2d");
ctx.__proto__.fillStar = function(r)
//ctx.__proto__ === CanvasRenderingContext2D.prototype
{
this.beginPath();
for(let i=0;i<=5;i )
{
this.lineTo(
Math.cos((18 i*72)/180*Math.PI)*r this.lastMoveTo.x,
-Math.sin((18 i*72)/180*Math.PI)*r this.lastMoveTo.y
);
this.lineTo(
Math.cos((54 i*72)/180*Math.PI)*r/2 this.lastMoveTo.x,
-Math.sin((54 i*72)/180*Math.PI)*r/2 this.lastMoveTo.y
);
}
this.closePath();
this.fill();
}
ctx.lastMoveTo = {};
CanvasRenderingContext2D.prototype.oldMoveTo = CanvasRenderingContext2D.prototype.moveTo;
CanvasRenderingContext2D.prototype.moveTo = function(x,y)
{
this.oldMoveTo(x,y);
this.lastMoveTo.x = x;
this.lastMoveTo.y = y;
}
ctx.moveTo(400,400)
ctx.fillStar(100);
</script>
</body>
</html>
图像处理
图像不同于图形,图像是位图是由无数个彩色像素点组成,图形是点线面结合而成,两者的处理方式也不相同,所干涉的区域也不相同
图形处理相关函数:
drawImage(img,sx,sy,sw,sh,dx,dy,dw,dh) :导入指定图片到canvas当中。 九个参数 首个是图片资源,s开头的是原图像的参数,d开头的是指在canvas绘制的参数
语法格式:
代码语言:javascript复制<!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
class="canvas"
width="800"
height="800"
style="border:1px solid blue"
></canvas>
<script>
var ctx = document.querySelector(".canvas").getContext("2d");
var img = new Image();
img.src = "../PHP操作MySQL.png";
img.onload = () => {
ctx.drawImage(img, 740, 450, 260, 70, 0, 0, 800, 800);
};
</script>
</body>
</html>
案例:图像放大
代码语言:javascript复制<!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>
<style>
body,
html {
background: black;
}
input[type=range] {
-webkit-appearance: none;
width: 300px;
border-radius: 10px; /*这个属性设置使填充进度条时的图形为圆角*/
margin-top: 10px;
}
input[type=range]::-webkit-slider-thumb {
-webkit-appearance: none;
}
input[type=range]::-webkit-slider-runnable-track {
height: 10px;
border-radius: 10px; /*将轨道设为圆角的*/
box-shadow: 0 1px 1px #def3f8, inset 0 .125em .125em #0d1112; /*轨道内置阴影效果*/
}
input[type=range]::-webkit-slider-thumb {
-webkit-appearance: none;
height: 25px;
width: 25px;
margin-top: -5px; /*使滑块超出轨道部分的偏移量相等*/
background: #ffffff;
border-radius: 50%; /*外观设置为圆形*/
border: solid 0.125em rgba(205, 224, 230, 0.5); /*设置边框*/
box-shadow: 0 .125em .125em #3b4547; /*添加底部阴影*/
}
</style>
</head>
<body>
<canvas
class="canvas"
style="border:1px solid blue;margin: 0 auto;display: block"
></canvas>
<input
type="range"
style="display:block;width:100%;"
max="3.0"
min="0.5"
step="0.1"
value="1"
class="scale"
/>
<script>
var ctx = document.querySelector(".canvas").getContext("2d");
var img = new Image();
var scale = document.querySelector(".scale");
img.src = "../1.jpg";
img.onload = () => {
ctx.canvas.width = img.width;
ctx.canvas.height = img.height;
drawImageByScale(ctx, scale.value, img.width, img.height);
// scale.onchange = function() {
// ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
// drawImageByScale(ctx, scale.value, img.width, img.height);
// };
scale.onmousemove = function() {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
drawImageByScale(ctx, scale.value, img.width, img.height);
};
};
function drawImageByScale(ctx, scale, w, h) {
var imageWidth = w * scale;
var imageHeight = h * scale;
let x = ctx.canvas.width / 2 - imageWidth / 2,
y = ctx.canvas.height / 2 - imageHeight / 2;
ctx.drawImage(img, x, y, imageWidth, imageHeight);
}
</script>
</body>
</html>
//水印版
<!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>
<style>
body,
html {
background: black;
}
.bottom {
width: 100%;
position: fixed;
bottom: 30px;
}
input[type="range"] {
-webkit-appearance: none;
width: 300px;
border-radius: 10px; /*这个属性设置使填充进度条时的图形为圆角*/
margin-top: 10px;
position: relative;
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
}
input[type="range"]::-webkit-slider-runnable-track {
height: 10px;
border-radius: 10px; /*将轨道设为圆角的*/
box-shadow: 0 1px 1px #def3f8, inset 0 0.125em 0.125em #0d1112; /*轨道内置阴影效果*/
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
height: 25px;
width: 25px;
margin-top: -5px; /*使滑块超出轨道部分的偏移量相等*/
background: #ffffff;
border-radius: 50%; /*外观设置为圆形*/
border: solid 0.125em rgba(205, 224, 230, 0.5); /*设置边框*/
box-shadow: 0 0.125em 0.125em #3b4547; /*添加底部阴影*/
}
</style>
</head>
<body>
<canvas
class="canvas"
style="border:1px solid blue;margin: 0 auto;display: block"
></canvas>
<div class="bottom">
<input
type="range"
style="display:block;width:100%;"
max="3.0"
min="0.5"
step="0.1"
value="1"
class="scale"
/>
</div>
<script>
var ctx = document.querySelector(".canvas").getContext("2d");
var img = new Image();
var scale = document.querySelector(".scale");
img.src = "./img.jpg";
var shuiying = document.createElement("canvas").getContext("2d");
shuiying.canvas.width = 400;
shuiying.canvas.height = 100;
shuiying.font = "bold 50px 微软雅黑";
shuiying.fillStyle = "white";
shuiying.textAlign = "center";
shuiying.textBaseline = "middle";
shuiying.fillText("xuyuxin", 200, 50, 400);
img.onload = () => {
ctx.canvas.width = img.width;
ctx.canvas.height = img.height;
drawImageByScale(ctx, scale.value, img.width, img.height,shuiying);
// scale.onchange = function() {
// ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
// drawImageByScale(ctx, scale.value, img.width, img.height);
// };
scale.onmousemove = function() {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
drawImageByScale(ctx, scale.value, img.width, img.height, shuiying);
};
};
function drawImageByScale(ctx, scale, w, h, c) {
var imageWidth = w * scale;
var imageHeight = h * scale;
let x = ctx.canvas.width / 2 - imageWidth / 2,
y = ctx.canvas.height / 2 - imageHeight / 2;
ctx.drawImage(img, x, y, imageWidth, imageHeight);
if(scale>=1)
{
ctxdrawImage(c.canvas, -40, ctx.canvas.height - 100);
}
else
{
ctx.drawImage(c.canvas, x, imageHeight-50);
}
}
</script>
</body>
</html>
案例:放大镜
代码语言:javascript复制<!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>
<style>
body,
html {
background: black;
}
.bottom {
width: 100%;
position: fixed;
bottom: 30px;
}
input[type="range"] {
-webkit-appearance: none;
width: 300px;
border-radius: 10px; /*这个属性设置使填充进度条时的图形为圆角*/
margin-top: 10px;
position: relative;
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
}
input[type="range"]::-webkit-slider-runnable-track {
height: 10px;
border-radius: 10px; /*将轨道设为圆角的*/
box-shadow: 0 1px 1px #def3f8, inset 0 0.125em 0.125em #0d1112; /*轨道内置阴影效果*/
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
height: 25px;
width: 25px;
margin-top: -5px; /*使滑块超出轨道部分的偏移量相等*/
background: #ffffff;
border-radius: 50%; /*外观设置为圆形*/
border: solid 0.125em rgba(205, 224, 230, 0.5); /*设置边框*/
box-shadow: 0 0.125em 0.125em #3b4547; /*添加底部阴影*/
}
</style>
</head>
<body>
<canvas
class="canvas"
style="border:1px solid blue;margin: 0 auto;display: block"
></canvas>
<script>
var ctx = document.querySelector(".canvas").getContext("2d");
var offsetCanvas = document.createElement("canvas").getContext("2d");
var img = new Image();
var scale;
img.src = "./img-lg.jpg";
img.onload = () => {
ctx.canvas.width = 1152;
ctx.canvas.height = 768;
offsetCanvas.canvas.width = img.width;
offsetCanvas.canvas.height = img.height;
scale = offsetCanvas.canvas.width / ctx.canvas.width;
ctx.drawImage(img, 0, 0, ctx.canvas.width, ctx.canvas.height);
offsetCanvas.drawImage(img, 0, 0);
};
ctx.canvas.onmousedown = function(e) {
var x = e.clientX - this.getBoundingClientRect().left,
y = e.clientY - this.getBoundingClientRect().top;
Draw(ctx, true, x, y);
this.onmousemove = e => {
var x = e.clientX - this.getBoundingClientRect().left,
y = e.clientY - this.getBoundingClientRect().top;
Draw(ctx, true, x, y);
};
this.onmouseup = () => {
ctx.canvas.onmousemove = null;
Draw(ctx, false);
};
this.onmouseout = () => {
ctx.canvas.onmousemove = null;
Draw(ctx, false);
};
};
function Draw(ctx, flag, x, y) {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.drawImage(img, 0, 0, ctx.canvas.width, ctx.canvas.height);
if (flag) {
drawImageRect(ctx, x, y);
}
}
function drawImageRect(ctx, x, y) {
var imageLgX = x * scale,
imageLgY = y * scale;
var r = 200;
var sx = imageLgX - r,
sy = imageLgY - r;
var dx = x - r,
dy = y - r;
ctx.save();
ctx.beginPath();
ctx.arc(x,y,r,0,Math.PI*2);
ctx.stroke();
ctx.clip()
ctx.drawImage(offsetCanvas.canvas, sx, sy, r * 2, r * 2, dx, dy, r * 2, r * 2);
ctx.closePath();
ctx.restore();
}
</script>
</body>
</html>
像素处理
相关函数:
getImageData(x,y,w,h):获取指定图像像素数据 返回一个对象,里面有 data像素数据
putImageData(img,dx,dy,dirtx,dirty,dirtw,dirth):输出处理后的图像到指定位置
createImageData(w,h):创建一个空的图像
像素处理算法:
语法格式:
代码语言:javascript复制//像素自动变紫
<!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>
<style>
body,
html {
/* background: black; */
height: 2000px;
}
</style>
</head>
<body>
<canvas
class="canvas"
style="border:1px solid blue;float:left"
width="500"
height="500"
></canvas>
<canvas
class="canvas"
style="border:1px solid blue;float:right"
width="500"
height="500"
></canvas>
<div class="btnbox" style="display: block;">
<a href="javascript:void(0)" onclick="fillter()">fillter</a>
</div>
<script>
var ctx1 = document.querySelectorAll(".canvas")[0].getContext("2d");
var ctx2 = document.querySelectorAll(".canvas")[1].getContext("2d");
var n =0;
var imageData;
var data;
var img = new Image();
img.src = "./img.jpg";
img.onload = function() {
ctx1.drawImage(img, 0, 0, 500, 500);
};
function fillter() {
imageData = ctx1.getImageData(0, 0, 500, 500);
data = imageData.data;
for (let i = 0; i < ctx2.canvas.width * ctx2.canvas.height; i ) {
data[4 * i 0] = n;
// data[4 * i 1] = n;
data[4 * i 2] = n;
// data[4 * i 3] = Math.ceil(Math.random()*255);
}
ctx2.putImageData(imageData, 0, 0, 0, 0, 500, 500);
}
setInterval(function(){
n ;
if(n===255)
{
n=Math.ceil(Math.random()*255)
}
fillter(n);
},1);
</script>
</body>
</html>
案例:像素滤镜
代码语言:javascript复制<!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>
<style>
body,
html {
/* background: black; */
height: 2000px;
}
.btnbox > a {
float: left;
margin: 10px 20px;
}
</style>
</head>
<body>
<canvas class="canvas" style="float:left" width="500" height="500"></canvas>
<canvas
class="canvas"
style="float:right"
width="500"
height="500"
></canvas>
<div class="btnbox" style="display: block;">
<a href="javascript:void(0)" onclick="grey()">灰度 Grey Effect</a>
<a href="javascript:void(0)" onclick="black()">黑白 black&white Effect</a>
<a href="javascript:void(0)" onclick="revers()">反色 revers Effect</a>
<a href="javascript:void(0)" onclick="Blur()">模糊 blur Effect</a>
<a href="javascript:void(0)" onclick="mosaice()">马赛克 mosaice Effect</a>
</div>
<script>
var ctx1 = document.querySelectorAll(".canvas")[0].getContext("2d");
var ctx2 = document.querySelectorAll(".canvas")[1].getContext("2d");
var imageData;
var data;
var img = new Image();
img.src = "../1.jpg";
img.onload = function() {
ctx1.drawImage(img, 0, 0, 500, 500);
};
function mosaice() {
var imgData = ctx1.getImageData(0, 0, 500, 500);
var data = imgData.data;
var tmpimgData = ctx1.getImageData(0, 0, 500, 500);
var tmpData = tmpimgData.data;
var size = 16,
totalnum = Math.pow(size, 2);
for (var i = 0; i < ctx2.canvas.height; i = size) {
for (var j = 0; j < ctx2.canvas.width; j = size) {
var totalr = 0,
totalg = 0,
totalb = 0;
for (var dx = 0; dx < size; dx ) {
for (var dy = 0; dy < size; dy ) {
let x = i dx,
y = j dy;
let p = x * ctx2.canvas.width y;
totalr = tmpData[p * 4 0];
totalg = tmpData[p * 4 1];
totalb = tmpData[p * 4 2];
}
}
var p = i * ctx2.canvas.width j;
var resr = totalr / totalnum;
var resg = totalg / totalnum;
var resb = totalb / totalnum;
for (var dx = 0; dx < size; dx ) {
for (var dy = 0; dy < size; dy ) {
var x = dx i,
y = dy j;
var p = x * ctx2.canvas.width y;
data[4 * p 0] = resr;
data[4 * p 1] = resg;
data[4 * p 2] = resb;
}
}
}
}
ctx2.putImageData(imgData, 0, 0, 0, 0, 500, 500);
}
function revers() {
imageData = ctx1.getImageData(0, 0, 500, 500);
data = imageData.data;
for (let i = 0; i < ctx2.canvas.width * ctx2.canvas.height; i ) {
let r = 255 - data[4 * i 0],
g = 255 - data[4 * i 1],
b = 255 - data[4 * i 2];
data[4 * i 0] = r;
data[4 * i 1] = g;
data[4 * i 2] = b;
}
ctx2.putImageData(imageData, 0, 0, 0, 0, 500, 500);
}
function Blur() {
var imgData = ctx1.getImageData(0, 0, 500, 500);
var data = imgData.data;
var tmpimgData = ctx1.getImageData(0, 0, 500, 500);
var tmpData = tmpimgData.data;
var blurR = 2,
totalnum = Math.pow(2 * blurR 1, 2);
for (var i = blurR; i < ctx2.canvas.height - blurR; i ) {
for (var j = blurR; j < ctx2.canvas.width - blurR; j ) {
var totalr = 0,
totalg = 0,
totalb = 0;
for (var dx = -blurR; dx <= blurR; dx ) {
for (var dy = -blurR; dy <= blurR; dy ) {
let x = i dx,
y = j dy;
let p = x * ctx2.canvas.width y;
totalr = tmpData[p * 4 0];
totalg = tmpData[p * 4 1];
totalb = tmpData[p * 4 2];
}
}
var p = i * ctx2.canvas.width j;
data[p * 4 0] = totalr / totalnum;
data[p * 4 1] = totalg / totalnum;
data[p * 4 2] = totalb / totalnum;
}
}
ctx2.putImageData(imgData, 0, 0, 0, 0, 500, 500);
}
function grey() {
imageData = ctx1.getImageData(0, 0, 500, 500);
data = imageData.data;
for (let i = 0; i < ctx2.canvas.width * ctx2.canvas.height; i ) {
let r = data[4 * i 0],
g = data[4 * i 1],
b = data[4 * i 2];
let grey = r * 0.3 g * 0.59 b * 0.11;
data[4 * i 0] = grey;
data[4 * i 1] = grey;
data[4 * i 2] = grey;
}
ctx2.putImageData(imageData, 0, 0, 0, 0, 500, 500);
}
function black() {
imageData = ctx1.getImageData(0, 0, 500, 500);
data = imageData.data;
for (let i = 0; i < ctx2.canvas.width * ctx2.canvas.height; i ) {
let r = data[4 * i 0],
g = data[4 * i 1],
b = data[4 * i 2];
let grey = r * 0.3 g * 0.59 b * 0.11;
if (grey > 255 / 2) {
v = 255;
} else {
v = 0;
}
data[4 * i 0] = v;
data[4 * i 1] = v;
data[4 * i 2] = v;
}
ctx2.putImageData(imageData, 0, 0, 0, 0, 500, 500);
}
</script>
</body>
</html>
案例:颜色板
代码语言:javascript复制<!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>
<style>
body,
html {
/* background: black; */
height: 2000px;
}
.btnbox > a {
float: left;
margin: 10px 20px;
}
</style>
</head>
<body>
<canvas class="canvas" style="float:left" width="800" height="800"></canvas>
<div class="btnbox" style="display: block;"></div>
<script>
var ctx = document.querySelectorAll(".canvas")[0].getContext("2d");
var img = ctx.createImageData(800, 800);
var data = img.data;
for (var i = 0; i < ctx.canvas.height; i ) {
for (var j = 0; j < ctx.canvas.width; j ) {
var p = i * ctx.canvas.width j;
data[4 * p 0] = parseInt(
Math.pow(Math.cos(Math.atan2(j - 400, i - 400) / 2), 2) * 255
);
data[4 * p 1] = parseInt(
Math.pow(
Math.cos(
Math.atan2(j - 400, i - 400) / 2 - (2 * Math.acos(-1)) / 3
),
2
) * 255
);
data[4 * p 2] = parseInt(
Math.pow(
Math.cos(
Math.atan2(j - 400, i - 400) / 2 (2 * Math.acos(-1)) / 3
),
2
) * 255
);
data[4 * p 3] = 255;
}
}
ctx.putImageData(img, 0, 0, 0, 0, 800, 800);
</script>
</body>
</html>
什么是Ajax?
Ajax是一种可以与服务器交换数据并更新部分页面内容,同时可以在不让整个网页重新加载的情况下更新网页的一种技术
Ajax请求过程:
1:创建一个异步对象
代码语言:javascript复制var xmlHttp = new XMLHttpRequest();
2:设置请求方式和请求地址
代码语言:javascript复制/*
参数顺序,描述
(1)method:请求的类型;GET 或 POST
(2)url:文件在服务器上的位置
(3)async:true(异步)或 false(同步) (一般为true,因ajax的精髓就是异步)
*/
xmlHttp.open("GET||POST","url 如(./ajax.php)",true)
//注意点:url中不能出现中文,只能数字、字母、ASCII码、下划线
// GET方式的 url格式:./ajax.php?t=123&321......
//如果出现中文也可以用encodeURIComponent方法转换
// POST方式的url不能在后面接字符串传递参数
xmlHttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
//setRequestHeader 必须放在设置请求与发送请求之间
//下一步在发送请求send中传递参数即可
xmlHttp.send("name=xuyuxin&age=18")
3:发送请求
代码语言:javascript复制 xmlHttp.send();
4.监听状态变化
代码语言:javascript复制//监听事件: onreadystatechange 每当请求状态发生变化,就会触发此函数
xmlHttp.onreadystatechange = function (ev2){
/*
readyState 状态变化有以下5种
0:请求未初始化
1:服务器连接已建立
2:请求已接收
3:请求处理中
4:请求已完成,且响应已就绪
*/
if(xmlHttp.readyState === 4){
//请求已完成,并不代表请求成功,因此还需判断是否请求成功
//status是专门判断请求是否成功的状态码
// 状态码大于或等于200并且不能超过300以上,300以上除了304以外全都是请求失败
if(xmlHttp.status >= 200 && xmlHttp.status < 300 || xmlHttp.status === 304){
console.log('请求成功')
}else{
console.log('请求失败')
}
}
}
http请求成功或失败状态码资料查询
IE低版本浏览器兼容问题
代码语言:javascript复制由于在IE6-IE5以下不支持XMLHttpRequest这个属性,因此会产生错误,在低级浏览器中可以使用ActiveXObject来实现同样的效果
var xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
代码语言:javascript复制在IE低版本中ajax还有缓存的问题,解决这个问题,要url地址不断改变,不能为常量,即可解决
xmlhttp.open("GET","ajax.php?" (new Date().getTime()),true)
解决兼容性通用方法
代码语言:javascript复制由于在Ajax中浏览器支持的属性不同,单一方案不能支持全部浏览器,有两种解决方案,因此可以把这两种方案合成一种,以便使用
if(window.XMLHttpRuquest){
var xmlHttp = new XMLHttpRequest();
}else{
var xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
=====================================================================================
var xmlHttp = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXOject("Microsoft.XMLHTTP");
封装Ajax
代码语言:javascript复制/**
* @param {请求的类型}option.type
* @param {发送请求的地址} option.url
* @param {发送请求的数据}option.data
* @param {超时时间} option.timeout
* @param {请求成功后执行的函数*} option.sucess
* @param {请求失败后执行的函数*} option.error
*/
function createAjax(option) {
//0.把传入对象处理成字符串,服务器才可接收
var toStringObj = objToString(option.data);
//1.创建ajax对象,并判断游览器支持那个属性
var xmlHttp = window.XMLHttpRequest
? new XMLHttpRequest()
: new ActiveXObject("Microsoft.XMLHTTP");
var timer;
if (option.type.toloworCase === "get") {
//2.设置请求方式和地址
xmlHttp.open("GET", option.url "?" toStringObj, true);
//3.发送请求
xmlHttp.send();
//4.监听请求状态
} else {
// POST请求方式
xmlHttp.open(option.type, option.url, true);
xmlHttp.setRequestHeader(
"Content-type",
"application/x-www-form-urlencoded"
);
xmlHttp.send(toStringObj);
}
xmlHttp.onreadystatechange = function() {
//请求完成,并不代表请求成功
if (xmlHttp.readyState === 4) {
//判断请求是否成功
if (
(xmlHttp.status >= 200 && xmlHttp.status < 300) ||
xmlHttp.status === 304
) {
clearInterval(timer);
option.sucess(xmlHttp);
} else {
option.error(xmlHttp);
}
}
};
//判断外界是否传入超时时间
if (option.timeout) {
timer = setInterval(function() {
//超时时间到后执行停止此次发送请求,默认为失败
xmlHttp.abort();
clearInterval(timer);
}, option.timeout);
}
}
//把obj转为字符串
function objToString(data) {
var res = [];
data.time = new Date().getTime();
for (var key in data) {
//encodeURLComponent函数对,对象名和属性进行转换,以防出现url中不能出现的字符而出错
res.push(encodeURIComponent(key) "=" encodeURIComponent(data[key]));
}
return res.join("&");
}
//调用方式
createAjax({
data:{
name: that.getAttribute('name')
},
type:"POST",
timeout:3000,
url:"./ajaxLesson2.php",
sucess:function(xml){
console.log('请求成功');
},
error:function(xml){
console.log("请求失败");
},
});
获取服务器响应数据方式
- responseText 可以获取服务器以字符串形式返回的数据
- responseXML 可以获取服务器以XML形式返回的数据
//调用方式
// ajax对象.要获取的方式
xmlHttp.responseText
通过XML传输数据
XML数据基本格式
1.开头前缀指定版本和编码(必要)
代码语言:javascript复制<?xml version="1.0" encoding="UTF-8"?>
2.根目录(必要 和html标签一样要闭合)
代码语言:javascript复制<root>
</root>
3.之后标签名不受限制,完整版
代码语言:javascript复制<?xml version="1.0" encoding="UTF-8"?>
<root>
<nz>
<title>甜美女装</title>
<des>人见人爱,花间花开,甜美系列</des>
<image>images/1.jpg</image>
</nz>
<bb>
<title>奢华驴包</title>
<des>送女友,送情人,送学妹,一送一个准系列</des>
<image>images/2.jpg</image>
</bb>
<tx>
<title>键盘拖鞋</title>
<des>程序员专属拖鞋, 屌丝气息浓郁, 你值得拥有</des>
<image>images/3.jpg</image>
</tx>
</root>
PHP基本XML配置格式
代码语言:javascript复制<?php
//向客户端发送原始的 HTTP 报头。
header("content-type:text/xml;charset=utf-8");
//file_get_contents() 函数是用于将文件的内容读入到一个字符串中的首选方法。如果操作系统支持,还会使用 内存映射技术来增强性能。
echo file_get_contents("xml文件地址如(./ajax.xml)")
?>
Ajax获取XML数据格式
代码语言:javascript复制//获取XML传输而来的数据要使用 responseXML方式获取
var Data = xml.responseXML; //返回的是一个document文档对象
//接着使用javascript获取遍历DOM元素
var titleinfo = Data.querySelector(name '>title'),
des = Data.querySelector(name '>des'),
image = Data.querySelector(name '>image');
//最后就可以对DOM里面存储的数据进行操作了
console.log(des.innerHTML);
通过JSON传输数据
JSON资料
JSON数据基本格式
代码语言:javascript复制{
"nz":{
"title":"甜美女装",
"des":"人见人爱,花间花开,甜美系列",
"image":"./images/1.jpg"
},
"bb":{
"title":"奢华驴包",
"des":"送女友,送情人,送学妹,一送一个准系列",
"image":"./images/2.jpg"
},
"tx":{
"title":"键盘拖鞋",
"des":"程序员专属拖鞋, 屌丝气息浓郁, 你值得拥有",
"image":"./images/3.jpg"
}
}
//在 JS 语言中,一切都是对象。因此,任何支持的类型都可以通过 JSON 来表示,例如字符串、数字、对象、数组等。但是对象和数组是比较特殊且常用的两种类型:
//JSON 键/值对
//JSON 键值对是用来保存 JS 对象的一种方式,和 JS 对象的写法也大同小异,键/值对组合中的键名写在前面并用双引号 "" 包裹,使用冒号 : 分隔,然后紧接着值:
"{"firstName": "Json"}"
这很容易理解,等价于这条 JavaScript 语句:
{firstName : "Json"}
//JSON 与 JS 对象的关系
//很多人搞不清楚 JSON 和 Js 对象的关系,甚至连谁是谁都不清楚。其实,可以这么理解:
//JSON 是 JS 对象的字符串表示法,它使用文本表示一个 JS 对象的信息,本质是一个字符串。
//如:
var obj = {a: 'Hello', b: 'World'}; //这是一个对象,注意键名也是可以使用引号包裹的
var json = '{"a": "Hello", "b": "World"}'; //这是一个 JSON 字符串,本质是一个字符串
JSON和JS对象互转
代码语言:javascript复制//要实现从JSON对象转换为JS字符串,使用 JSON.parse() 方法:
var obj = JSON.parse('{"a": "Hello", "b": "World"}'); //结果是 {a: 'Hello', b: 'World'}
//要实现从JS对象转换为JSON字符串,使用 JSON.stringify() 方法:
var json = JSON.stringify({a: 'Hello', b: 'World'}); //结果是 '{"a": "Hello", "b": "World"}'
//当从服务器返回的数据不是标准json字符串时是无法使用parse的,那么可以试试用eval()强制转化和为js对象
非标准json转js对象
代码语言:javascript复制//当从服务器返回的数据不是标准json字符串时是无法使用parse的,那么可以试试用eval()强制转化和为js对象
//注意点: 转js对象必须加 "(" data ")"
var Data = eval("(" data ")")
JSON兼容性问题
在低版本的IE中, 不可以使用原生的JSON.parse方法, 但是可以使用json2.js这个框架来兼容 json2.js下载地址:
PHP基本JSON格式
代码语言:javascript复制echo file_get_contents(" JSON文件地址 如(./json.txt)");
跨域
ajax的请求过程:ajax发送请求–浏览器–服务器 响应过程则是请求过程的颠倒 当ajax发送请求到浏览器,浏览器发送到服务器,处理并响应后,原路返回到浏览器,此时会验证其请求来源的域名跟发送请求时是否一样,是则过,否则会被浏览器截止并提示错误,这正是跨域所造成的,想要解决此问题,并不能从前端入手,应该从后端,只有在后端响应并返回后告诉浏览器是自己人即可。 那怎么告诉浏览器是自己人呢? 只要设置其响应头部信息 (Access-Control-Allow-Origin:域名)告诉浏览器即可,允许多个、单个、全部 (*)。
PHP 方式
代码语言:javascript复制/*
1、允许单个域名访问
*/
header("Access-Control-Allow-Origin:(域名)");
/*
2、允许多个域名访问
*/
$origin = isset($_SERVER['HTTP_ORIGIN']) ? $_SERVER['HTTP_ORIGIN'] : '';
$option = array(
('域名1'),
('域名2'),
....
);
if(in_array($origin,$option)) header("Access-Control-Allow-Origin:$origin");
/*
3、允许全部域名访问
*/
header("Access-Control-Allow-Origin:*");
node方式
代码语言:javascript复制/*
1、允许单个域名访问
*/
http.createServer(req,res)
{
res.setHeader("Access-Control-Allow-Origin","(域名)");
}
/*
2、允许多个域名访问
*/
let option = [
(域名1),
(域名2),
...
];
http.createServer(req,res)
{
let {origin} = req.headers;
let ori = option["origin"] ? option["origin"] : null;
res.setHeader("Access-Control-Allow-Origin",ori);
}
/*
3、允许全部域名访问
*/
http.createServer(req,res)
{
res.setHeader("Access-Control-Allow-Origin","*");
}
FormData
FormData是ajax2.0新添加的功能,其作用是让表单也能异步发送
语法格式:
代码语言:javascript复制//必须要new 一个FormData对象 参数是要应用的表单元素
//禁止表单默认行为
//其请求方式、请求地址跟随表单元素
//最后发送formdata对象即可
//原生方式
let form = document.querySelector("form");
document.querySelector("form").onsubmit = ()=>{
let xhr = new XMLHttpRequest();
let formdata = new FormData(form);
xhr.open(form.method,form.action,true);
xhr.send(formdata);
xhr.onreadystatechange =()=>{
if(xhr.readyState === 4)
{
if(xhr.status === 200)
{
console.log("成功");
}else
{
console.log("失败");
}
}
}
return false;
}
//jQuery方式
$(function(){
$("form").on("submit",function(){
console.log(1);
let formdata = new FormData(this);
$.ajax({
url:this.action,
type:this.method,
data:formdata,
//由于jq在发送请求时,会把请求数据自动处理为适合发送的数据格式,但是formdata对象本事就不用处理,系统识别会自动处理数据,如果被jq格式化后,数据就会出错,所以要关闭其数据格式化,以及发送的头部信息。
processData:false,
contentType:false
}).then((req)=>{
console.log("成功");
},(res)=>{
console.log("失败");
})
return false;
})
})
//如果不使用表单提交,可以使用以下另门方式
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="div1">
用户:<input type="text" id="user" /><br>
密码:<input type="password" id="pass" /><br>
文件:<input type="file" id="f1" /><br>
<input id="btn1" type="button" value="提交">
</div>
</body>
<script>
let oBtn=document.querySelector('#btn1');
oBtn.onclick=function (){
let formdata=new FormData();
formdata.append('username', document.querySelector('#user').value);
formdata.append('password', document.querySelector('#pass').value);
formdata.append('f1', document.querySelector('#f1').files[0]);
//
let xhr=new XMLHttpRequest();
xhr.open('post', 'http://localhost:8080/', true);
xhr.send(formdata);
xhr.onreadystatechange=function (){
if(xhr.readyState==4){
if(xhr.status==200){
alert('成功');
}else{
alert('失败');
}
}
};
};
</script>
</html>
fetch
代码语言:javascript复制fetch是官方用来解决原生js的ajax的繁杂步骤问题的一门新语法,大大简化了ajax操作,原理基于ajax
// get txt
window.onload=function (){
let oBtn=document.getElementById('btn1');
oBtn.onclick=async function (){
//1.请求
let res=await fetch('data/1.txt');
//2.解析
let str=await res.text();
alert(str);
};
};
//get json
window.onload=function (){
let oBtn=document.getElementById('btn1');
oBtn.onclick=async function (){
//1.请求
let res=await fetch('data/1.json');
//2.解析
let json=await res.json();
console.log(json);
};
};
//get blod
window.onload=function (){
let oImg=document.getElementById('img1');
let oBtn=document.getElementById('btn1');
oBtn.onclick=async function (){
//1.请求
let res=await fetch('data/1.png');
//2.解析
let data=await res.blob();
let url=URL.createObjectURL(data);
oImg.src=url;
};
};