<canvas></canvas>
canvas是一个矩形区域的画布,可以使用脚本javascript在其中绘制图形的HTML元素,是HTML5中新增的元素。 canvas自身并不具备绘制功能,canvas须依靠javascript才能绘制出图形;canvas也提供了多种绘制路径、矩形、圆形、字符以及添加图像的方法; canvas 的默认大小为300像素×150像素(宽×高,像素的单位是px)。
如果使用style/js(canvas.style.width/height)设置宽高,等同于把画布进行缩放,可能会使内容模糊
canvas正确设置宽高的方法:(属性单位必须是px)
canvas 的上下文、绘制环境
context对象就是js操作canvas的接口:[canvasElement].getContext('2d')来获取2D绘图上下文
3d:webgl
代码详见demo/canvas.html
// 清除之前的图片轨迹 canvas.width = canvas.width; // 一般不用这种方法
// 如果通过代码重新设置canvas画布的宽高,那么canvas画布里面的所有的内容都会被清空
ctx.clearRect(0,0,canvas.width,canvas.height);
了解:非零环绕规则,交叉路径的填充问题,运用“非零环绕规则”,顺逆时针穿插次数决定是否填充。
注意:绘制的线段会出现跨像素,颜色变浅,占2像素的问题(+.5)
绘制椭圆&圆弧
arc(圆心x,圆心y,半径,起始弧度(x,水平方向),结束弧度,绘制方向counterClockWise(默认顺时针[false]);
弧度->角度:30 * Math.PI/180
圆形上面的点的坐标的计算公式:x = x0 + Math.cos(rad) * R // x0:起始点;R:距离,注意都是弧度
绘制文字 canvas处理文本的能力很弱
fillText(text,x,y[,maxWidth])
strokeText()
font 书写有顺序要求:大小不能写在最后 ctx.font = 'italic 50px blod Arial';
textBaseline = 'bottom' // 设置字体底线对齐绘制基线 顶线:最高位置;基线:x下边;中线:x中间;底线:最底下位置;
行高的定义:两行文本基线的距离就是行高。
textAlign = 'left' // 设置字体对齐的方式
ctx.measureText(item.title).width; // 获取文字所占宽度
绘制图片&视频
canvas 绘制图片效率比其他高
视频绘制其实就是一帧一帧的绘制
1. drawImage(image,x,y);
2. drawImage(image,x,y,w,h);
3. 图片切片后绘制:s 原图像 d 绘制画布
drawImage(image,sx,sy,sw,sh,dx,dy,dw,dh);
// 1. 创建图片的dom对象
var img = new Image();
// 只要设置了src属性,当前img对象立即去加载图片
img.src = '../images/what.jpg';
// 等待图片加载完成后,把图片绘制到canvas上
img.onload = function(){
// 2. 绘制图片(3类)
// 2.1 绘制图片默认大小
ctx.drawImage(img,50,400);
// 2.2 绘制图片并设置大小(缩放)
ctx.drawImage(img,50,600,100,100);
// 2.3 图片切片后绘制
ctx.drawImage(img,60,50,60,60,200,600,60,60)
}
默认上来就有一个状态
状态里面:当前状态里面的绘制样式
beginPath(); 开启一个新路径,开启新状态的绘图;来启一个新的状态,新状态可以继承之前状态的样式,但是当前状态设置所有的样式,只能作用于当前的状态。
颜色:接受颜色名,16进制数据,rgb值,rgba
透明度(整个画布的透明度)(了解) globalAlpha = value[0,1];
线型设置(了解)
线宽,设置或返回当前的线条宽度
lineWidth = value
两端样式,设置或返回线条的结束端点(线头、线冒)样式
lineCap = type
butt:默认值,向线条的每个末端添加平直的边缘; round:圆形,向线条的每个末端添加圆形线冒; square:方形(会增加线的宽度),向仙台哦的每个末端添加方形线冒。
拼接样式,设置或返回两条线相交时,所创建的拐角类型
lineJoin = type
bevel:创建斜角; miter:默认,创建尖角; square round:创建圆角。
miterLimit 设置或返回最大斜接长度
绘制贝塞尔曲线(知道有)
创建两条切线的弧(知道有) 类比css3中的圆角 arcTo
渐变(了解)
一般不用,都是用图片代替,canvas绘制图片效率更高;线性渐变可以用于矩形、圆形、文字等颜色样式。
线性渐变
var linearGradient = ctx.createLinearGradient(50,850,150,950);
linearGradient.addColorStop(0,'red')
linearGradient.addColorStop(.2,'skyblue')
linearGradient.addColorStop(.7,'green')
linearGradient.addColorStop(1,'pink');
ctx.fillStyle = linearGradient;
ctx.fillRect(50,850,100,100);
径向渐变 ctx.createRadialGradient(x0,y0,r0,x1,y1,r1); x0:渐变的开始圆的x坐标;x1:渐变的结束圆的x坐标;r0:开始圆的半径
设置png图片的阴影,图片透明部分不会被投影
ctx.fillStyle = 'yellow';
ctx.shadowColor = 'red'; 设置或返回用于阴影的颜色
ctx.shadowBlur = 30; 设置或返回用于阴影模糊级别,大于1的正整数,树枝越高,模糊程度越大
ctx.shadowOffsetX = 20; 设置或返回阴影距形状的水平距离
ctx.shadowOffsetY = 20; 设置或返回阴影距形状的垂直距离
ctx.fillRect(50,850,100,100);
变换:坐标系变换,与CSS3的2D转换类似
注意:原有内容不会受变换影响
1弧度=180/π度,1度=π/180弧度
角度A1转换弧度A2:A2=A1*π/180
弧度A2转换角度A1:A1=A2*π/PI
一般配合位移画布使用。
save() 保存当前画笔的状态,可以把当前绘制环境进行保存到缓存中。
restore() 返回之前保存过的路径状态和属性,获取最近缓存的ctx。
ctx.fillRect(0,0,100,100);
ctx.save();
// ctx.translate(100,100);
ctx.rotate(30*Math.PI/180);
ctx.fillStyle = 'tomato';
ctx.fillRect(0,0,100,100);
ctx.restore();
ctx.fillRect(100,0,50,50);
原理:是先定义一个初始的状态,然后定义一个定时器,定时器内执行一个方法,记得在这个方法中要对当前的画面清除,然后在这个方法中重新绘制需要变化的效果,由于人眼存在残影,所以,短时间内中断的变化可以看成是连续的变化。
动画其实是由不同的静态画面组成,每一幅静态画面我们叫做一帧(frame),当众多的静态画面按照一定的规则快速运动时,我们的眼睛就会欺骗我们的大脑,从而形成物体运动的假象。
把canvas绘制的内容输出成base64内容
语法:canvas.toDataURL(type, encoderOptions);
例如:canvas.toDataURL('image/jpg', 1);
参数说明:
var canvas = document.getElementById('#canvas');
var dataURL = canvas.toDataURL();
console.log(dataURL);
var img = document.querySelector('#img-demo'); // 拿到图片的dom对象
img.src = canvas.toDataURL('image/png'); // 将画布的内容给图片标签显示
var canvas1 = document.querySelector('#cavsElem1');
var canvas2 = document.querySelector('#cavsElem2');
var ctx1 = canvas1.getContext('2d');
var ctx2 = canvas2.getContext('2d');
ctx1.fillRect(20,20,40,40); // 在第一个画布上绘制矩形
ctx2.drawImage(canvas1,10,10); // 将第一个画布整体绘制到第二个画布上
我们使用canvas绘制了一个图形,一旦绘制成功了,canvas就像素化了他们。canvas没有能力从画布上再次得到这个图形,也就是说我们没有能力去修改已经在画布上的内容,这个就是canvas比较轻量的原因。flash重的原因之一就是它可以通过对应的api得到已经在“画布”上的内容然后进行绘制。
canvas上的画布元素,就像被像素化了,所以不能通过style.left方法进行修改,而是必须重新绘制
代码演示部分
// canvas方法参数智能提示
/* @type {HTMLCanvasElement} */
// 得到画布
var canvas = document.getElementById('canvas')
// 获取2d的画笔对象
var ctx = canvas.getContext('2d')
// 设置颜色
ctx.fillStyle = 'red'
var left = 100
// 动画过程
setInterval(()=>{
// 清除画布;0,0代表从什么位置开始清除;500,600代表清除的宽度和高度
ctx.clearRect(0,0,500,600)
// 更新信号量
left++
// 重新绘制
ctx.fillRect(left,100,100,100)
}, 30)
实际上,动画的生存就是相关静态画面连续播放了,这个就是动画的过程,我们把每一次绘制的静态画面叫做“一帧”,时间的间隔(定时器的间隔)就表示帧的间隔
动画过程在主定时器里面,每一帧都会调用实例的更新和渲染方法。
new 内部原理:
第一步:创建一个新的空对象(在内存中开辟一块空间);
第二部:把this指向到这个空对象;
第三部:把空对象的内部原型,指向构造函数的原型对象;
第四部:Cat 函数(函数对象):如果当前构造函数,执行到最后的时候,如果没有return,那么把构造函数中,构造的那个this对象返回给cat实例。
函数对象 Cat(this对象添加属性) ----> Cat.prototype show()(原型上添加方法) PI 对象的方法都放到原型上去定义(节省内存空间);原型上的属性只能通过原型对象自己去设置。尽量不要在原型中添加属性,公共的属性和常量的值可以放到原型对象中去。
| ^
V |
cat = new Cat 实例对象 age cat.PI = 'abc' 如果实例对象设置一个跟原型对象相同属性的值时,会自动添加一个对象自己的属性。 读取取的是原型的属性
因为canvas不能得到已经绘制的上一屏的对象,所以我们要维持对象的状态。在canvas中我们要使用面向对象的方式来编程,因为我们可以使用面向对象的方式来维持canvas的属性和状态;
var canvas = document.getElementById('canvas')
var ctx = canvas.getContext('2d')
function DrawRect(x, y, w, h, color) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.color = color ? color:'red';
}
// 更新方法
DrawRect.prototype.update = function() {
this.x++;
if(this.x > canvas.width) this.x = 0
}
// 渲染
DrawRect.prototype.render = function() {
// 设置颜色
ctx.fillStyle = this.color
ctx.fillRect(this.x, this.y, this.w, this.h)
}
// 实例化
var p1 = new DrawRect(0,100,canvas.widht,canvas.height)
setInterval(()=>{
ctx.clearRect(0,0,canvas.width,canvas.height)
p1.update()
p1.render()
}, 30)
// setTimeout(function run() {
// ctx.clearRect(0,0,canvas.width,canvas.height)
// p1.update()
// p1.render()
// setTimeout(run, 50)
// }, 50)
国产的egret引擎
比较火的3d引擎:threejs
Konva 特点:
// Konva使用基本案例
// 第一步:创建舞台
var stage = new Konva.Stage({
container: 'container', // 需要存放舞台的dom容器
width: window.innerWidth, // 设置全屏
height: window.innerWidth
});
// 第二步:创建层
var layer = new Konva.Layer(); // 创建一个层
stage.add(layer); // 把层添加到舞台
// 第三步:创建矩形
var rect = new Konva.Rect({// 创建一个矩形
x: 100, // 矩形的x坐标,相对其父容器的坐标
y: 100,
width: 100,
height: 100,
fill: 'gold',
stroke: 'navy',
strokeWidth: 4,
opacity: .2,
scale: 1.2,
rotation: 30, // 旋转的角度,是deg不是弧度
cornerRadius: 10, // 圆角的大小(像素)
draggable: true
})
// 第四步:把矩形添加到层上去
layer.add(rect);
// 第五步:把层渲染到舞台上
layer.draw();
多用百分比设置大小,可以适配
需求:我们app画笔回显字体,字体包不能每个页面都重新引入,太大了,能根据接口按需引入么?
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。