范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

Canvas从入门到实战

  1、什么是Canvas?
  HTML5 提供Canvas API,其本质上是一个DOM元素,可以看成是浏览器提供一块画布供我们在上面渲染2D或者3D图形。由于3D绘制上下文(webgl)目前在很多浏览器上兼容性较差,所以我们一般用于绘制2D图形。 
  2、为什么使用Canvas?
  Canvas是HTML5引入的标签,在此之前我们通常会使用SVG来绘制一些图形,那么两者之间有什么区别呢?SVG可缩放矢量图形(Scalable Vector Graphics)是基于可扩展标记语言XML描述的2D图形的语言,两者部分区别:
  SVG 图像是使用各种元素创建的,这些元素分别应用于矢量图像的结构、绘制与布局;而Canvas本身并不描述图像,而是通过Javascript完成绘制;  如上所述,SVG本身是DOM元素,每一个描述元素也是DOM元素,浏览器在进行渲染时需要进行大量计算以处理每一个元素;而在渲染Canvas的过程中,浏览器只需要渲染一张画布,其余的是通过Javascript引擎执行逻辑来绘制;  SVG(矢量图)不依赖分辨率,放大不会失真;而Canvas(位图)依赖分辨率,放大会失真;
  由于Canvas是通过Javascript来完成绘制的,所以可控性很强,我们可以比较精确的控制图形渲染的每一帧;从另一方面来说,如果在高频率渲染中要处理过多的DOM元素就意味着性能一定不会太好,渲染速度会下降很多。Canvas的高性能能够保障复杂场景中图形的渲染效率,所以目前很多领域都会使用Canvas,例如动画、游戏图形、数据可视化、照片处理和实时视频处理等。
  3、Canvas的基本使用
  要使用Canvas,我们需要先获取Canvas元素的引用继而通过getContext()方法获取图形的绘制上下文。 const canvas = document.getElementById("canvas") const ctx = canvas.getContext("2d")
  获取到图形绘制上下文后,我们就能使用CanvasRenderingContext2D接口上的绘图API了,接下来我们可以了解一些比较常规的使用。
  3.1、画布属性:
  width、height:画布的宽度以及高度,默认大小为300x150;  fillStyle:填充图形的样式,值可以是color string、CanvasGradient对象;  strokeStyle:轮廓图形的样式,值可以是color string、CanvasGradient对象;  lineWidth:绘制线条的宽度;  globalAlpha:画布的透明度,0-1的偏移值;  globalCompositeOperation:画布中新老图形重叠时的渲染方式,默认为source-over,新图形覆盖老图形;  ......  ctx.width = 300 ctx.height = 300 ctx.fillStyle = "#fff" ctx.strokeStyle = "blue" ctx.lineWidth = 5 ctx.globalAlpha = 0.3 ctx.globalCompositeOperation = "destination-out" // 新老图形重叠部分变透明 ......
  3.2、绘制图形:
  .fillRect(x,y,width,height):绘制一个填充的矩形,矩形左上角的坐标为(x,y),高宽分别为width、height;  .strokeRect(x,y,width,height):绘制一个矩形边框,矩形左上角的坐标为(x,y),高宽分别为width、height;  .clearRect(x,y,width,height): 清除指定矩形区域,让清除部分完全透明;  ctx.fillStyle = "red"  ctx.fillRect(100,100,100,100)   ctx.strokeStyle = "blue"   ctx.strokeRect(200,200,100,100)   ctx.clearRect(125,125,50,50) ctx.strokeRect(130,130,40,40)
  3.3、绘制路径:
  .beginPath():开始一段路径的绘制 ;  .closePath(): 从起始点到当前点,结束路径的绘制,非必需;  .fill():根据路径生成填充图形;  .stroke():通过路径生成轮廓图形;  .moveTo(x,y):声明一段路径的起始点;  .lineTo(x,y):绘制一条从当前坐标到(x,y)的线;  ctx.beginPath() ctx.moveTo(50,50) ctx.lineTo(100,100) ctx.lineTo(100,0) ctx.fill()   ctx.beginPath() ctx.moveTo(110,100) ctx.lineTo(150,100) ctx.lineTo(150,200) ctx.lineTo(110,200) ctx.closePath() // 轮廓图形不会根据从当前坐标到起始坐标生成轮廓,所以需要闭合路径 ctx.stroke()
  3.4、绘制圆弧:
  .arc(x,y,radius,startAngle,endAngle,anticlockwise):画一个以(x,y)为圆心的以 radius 为半径的圆弧(圆),从 startAngle 开始到 endAngle 结束,按照 anticlockwise 给定的方向(默认为顺时针,false)来生成;  arcTo(x1,y1,x2,y2,radius):根据给定的两条切线中的一组切点坐标生成半径为radius的圆弧;
  注意:arc函数中的角度的单位是弧度而不是度, 弧度= (Math.PI/180)*度  // 圆左上部分 ctx.beginPath() ctx.arc(100,100,50,Math.PI,Math.PI*3/2,false) ctx.strokeStyle = "#ff6700" ctx.stroke()   // 圆右上部分 ctx.beginPath() ctx.arc(100,100,50,Math.PI*3/2,0,false) ctx.strokeStyle = "#6700ff" ctx.stroke()   // 圆右下部分 ctx.beginPath() ctx.arc(100,100,50,0,Math.PI/2,false) ctx.strokeStyle = "#00FFFF" ctx.stroke()   // 圆左下部分 ctx.beginPath() ctx.arc(100,100,50,Math.PI/2,Math.PI,false) ctx.strokeStyle = "#8B008B" ctx.stroke()   // 两条切线的交点坐标为(0,0) ctx.beginPath() ctx.moveTo(100,0) ctx.arcTo(0,0,0,100,100) ctx.fillStyle = "blue" ctx.fill()
  3.5、渐变对象:
  .createLinearGradient(x1, y1, x2, y2): 创建一个沿参数坐标指定的直线的渐变,开始坐标为(x1,y1),结束坐标为(x2,y2);  .createRadialGradient(x1, y1, r1, x2, y2, r2):创建 根据参数确定两个圆的坐标的放射性渐变,开始圆形圆心为(x1,y1),半径为r1;结束圆形圆心为(x2,y2),半径为r2;
  创建好渐变对象之后,可以通过渐变对象上的 .addColorStop(offset,color) 为每一个渐变阶段填充颜色,offset为0-1的偏移值。  const gradient = ctx.createLinearGradient(50, 50, 250, 50) gradient.addColorStop(0, "blue") gradient.addColorStop(0.5, "green") gradient.addColorStop(1, "red") ctx.fillStyle = gradient ctx.fillRect(0, 0, 300, 90)   const radialGradient = ctx.createRadialGradient(200,200,100,200,200,50); radialGradient.addColorStop(0,"yellow"); radialGradient.addColorStop(1,"green"); ctx.fillStyle = radialGradient; ctx.fillRect(100,100,200,200);
  3.6、像素操作:
  .drawImage(image,x,y,width,height):image可以是image对象、canvas元素、video元素;  .getImageData(x,y,width,height):获取坐标为(x,y)一定区域内图像的像素数据;  const p = document.querySelector("p") let mousedown = false;   function getRandom() {   return Math.round(255 * Math.random()); }   function getColor() {   return `rgb(${getRandom()},${getRandom()},${getRandom()})`; }   const gradient = ctx.createLinearGradient(0, 0, 300, 300); gradient.addColorStop(0, getColor()); gradient.addColorStop(0.6, getColor()); gradient.addColorStop(1, getColor());   function clear() {   ctx.fillStyle = gradient;   ctx.fillRect(0, 0, canvas.width, canvas.height); }   ctx.beginPath(); ctx.fillStyle = gradient; ctx.fillRect(0, 0, 300, 300);   function selector(x = 150, y = 150) {   clear();   ctx.beginPath();   ctx.arc(x, y, 5, 0, Math.PI * 2);   ctx.strokeStyle = "#fff";   ctx.stroke();   const { data } = ctx.getImageData(x, y, 1, 1); // 获取(x,y)点对应的imageData   const color = `rgba(${data[0]},${data[1]},${data[2]},${data[3] / 255})`   p.innerText = `color: ${color}`;   p.style.backgroundColor = color }   function handleSelector(e) {   const x = e.offsetX;   const y = e.offsetY;   selector(x, y); }   canvas.addEventListener("mousedown", (e) => {   mousedown = true;   handleSelector(e) });   canvas.addEventListener("mouseup", () => {   mousedown = false; });   canvas.addEventListener("mousemove", (e) => {   if (mousedown) {     handleSelector(e)   } });   selector();
  3.7、画布状态:
  .save():将当前画布的状态推入到栈中,例如fillStyle、2D转换等;  .restore():将栈顶元素弹出,恢复上一次推入栈中画布的状态;
  当我们需要通过空间转换来绘制图形时,保存与恢复画布的状态是很关键的,因为我们是在同一块画布上绘制图形,而变换都是基于画布的,这与我们平时使用到的CSS 2D转换截然不同,所以我们在下一步绘制时要确认此时画布的状态是否是我们的理想状态。 ctx.save() // 保存画布初始状态 ctx.translate(100,100) // 将画布原点转移至(100,100) ctx.fillStyle = "red" ctx.fillRect(0,0,50,50)   ctx.restore() // 恢复画布状态,此时画布原点为(0,0) ctx.fillStyle = "blue" ctx.fillRect(0,0,50,50)
  3.8、几何变化:
  .translate(x,y):画布默认的原点是(0,0),此方法可以切换原点到(x,y)而不需要手动更改绘制图形的坐标;  .rotate(angle):将画布旋转一定的角度,angle单位为弧度;  .scale(sx,sy):sx为水平方向的缩放比例,sy为竖直方向的缩放比例;  .transform(a,b,c,d,e,f):依次为水平缩放、垂直倾斜、水平倾斜、垂直缩放、水平移动、垂直移动;
  const colors = ["red","orange","yellow","green","blue","purple"]; ctx.translate(150,150)      for(let i = 0; i < 6; i++) {   ctx.beginPath()   ctx.fillStyle = colors[i]   ctx.moveTo(0,0)   ctx.lineTo(100,0)   ctx.lineTo(100,50)   ctx.rotate(Math.PI/3)   ctx.fill() }
  4、综合实战
  const p = Math.PI;   function clock() {   const date = new Date();   const hour = date.getHours()   const s = date.getSeconds();   const m = date.getMinutes();   const h = !!(hour % 12) ? hour % 12 : 12;   ctx.clearRect(0, 0, canvas.width, canvas.height);     ctx.save(); // 保存画布初始状态     ctx.translate(150, 150);   ctx.rotate(-p / 2);     // 轮廓   ctx.beginPath();   ctx.lineWidth = 5;   ctx.strokeStyle = "#76b2ff";   ctx.arc(0, 0, 80, 0, p * 2);   ctx.stroke();     // 圆心   ctx.beginPath();   ctx.arc(0, 0, 2, 0, p * 2);   ctx.fill();     // 分针、秒针刻度   for (let i = 0; i < 60; i++) {     ctx.beginPath();     ctx.rotate(p / 30);     ctx.moveTo(75, 0);     ctx.lineWidth = 4;     ctx.strokeStyle = "#89f086";     ctx.lineTo(80, 0);     ctx.stroke();   }     // 时针刻度   for (let i = 0; i < 12; i++) {     ctx.beginPath()     ctx.rotate(p / 6)     ctx.moveTo(70, 0)     ctx.lineTo(80, 0)     ctx.stroke()   }     ctx.save(); // 保存画布变换之后的状态     // 秒针   ctx.beginPath();   ctx.rotate(s * (p / 30));   ctx.lineWidth = 2   ctx.strokeStyle = "#ff6700"   ctx.moveTo(0, 0);   ctx.lineTo(80, 0);   ctx.stroke();     // 恢复之前的状态再保存,时针、分针、秒针都是基于原点以及画布方向变换后绘制   ctx.restore();   ctx.save();     // 分针   ctx.beginPath();   ctx.rotate(m * (p / 30));   ctx.lineWidth = 3;   ctx.strokeStyle = "#6700ff"   ctx.moveTo(0, 0);   ctx.lineTo(70, 0);   ctx.stroke();     ctx.restore();     // 时针   ctx.beginPath();   ctx.rotate(h * (p / 6));   ctx.lineWidth = 4;   ctx.moveTo(0, 0);   ctx.lineTo(60, 0);   ctx.stroke();     ctx.restore(); // 恢复画布最初状态     document.querySelector("p").innerText = `Now:${h} : ${m} : ${s}  ${hour > 12 ? "pm" : "am"}`     window.requestAnimationFrame(clock); } clock();
  5、小结
  随着互联网的高速发展,用户对页面的视觉和交互有着越来越高的要求,传统的web开发无法得到满足,利用Canvas强大的绘图能力,可以让网页显示的内容更加的丰富多彩,也能给用户带来更好的视觉体验。
  作者:LLS-FE团队
  来源:微信公众号:流利说技术团队
  出处:https://mp.weixin.qq.com/s/bvkx3wOeMvIUU64cktX6iA

多地发布公积金新政调整内容较为广泛近日,多个楼市热点地区发布公积金新政。其中,吉林长春明确提出,提高多孩家庭公积金首贷额度,三孩家庭贷款额度可在单笔贷款最高额度基础上提高20万元。多地发布公积金新政1月2日,长春市2023年十大预测股市实现明显正收益,港股阶段性跑赢A股一2023年十大预测近日,中金公司发布文章指出,中国有望在全球率先实现复苏,2023年中国经济在三年疫情后有望翻开新篇。中金公司成立于1995年6月25日,是中国内地第一家中外合资案例李子柒持股99,真的赢了吗?2022年12月26日,李子柒(注又名李佳佳)与原合作伙伴杭州微念品牌管理有限公司(以下简称杭州微念)达成和解,如图1所示图1杭州微念与李子柒和解四川子柒文化传播有限公司(以下简称王府井前门隆福寺东城多个商圈今年将有新变化!北京日报客户端记者李瑶2022年,王府井成功入选北京市第一批全球首发中心,东安市场迎来华丽转型。2023年,王府井将持续推动商业设施提质升级,聚焦新燕莎银泰in88外文书店等商业体支持济南等地打造工业母机产业集群多项利好政策助力济南加快构建现代化产业体系布局济青新能源汽车两个基地,建设济青未来产业先导区根据日前省委省政府印发的山东省建设绿色低碳高质量发展先行区三年行动计划(20232025年),济南加快构建现代化产业体系,再迎来多金融限薪风暴下,投行MD公开炫富1。44亿存款近日,小红书上一张未经证实的9位数银行卡余额截图引发热议。有小红书博主发帖晒出了自己的银行卡余额,总共约1。44亿元。1。44亿是什么概念?根据2022年11月胡润百富与中信保诚人贵阳彩灯璀璨迎新年近日,贵阳市白云区2023年蓬莱仙界蘑力小镇首届彩灯艺术节亮灯,多姿多彩的彩灯艺术节处处洋溢着喜庆祥和迎新年的节日氛围,令不少市民陶醉其间。据了解,为加快推动白云区旅游产业复苏回暖别有洞天!天宁寺桥下变出游乐园和篮球场北京日报客户端记者张骜方非曾经灰色的桥下空间,即将成为亲子游乐和年轻人打球的乐园。1月5日,记者从西城区两会获悉,位于西城天宁寺桥近5000平方米的桥下空间将改建成为集亲子运动休闲注意这些是谣言!近日多条谣言在网络流传请大家注意防范!一景区6名阳康游客心衰死亡?回应来了近日,一则老君顶景区的阳康游客心衰死亡6人的消息在网络上传播开来,据秦皇岛老君顶旅游开发有限公司相关负责人2023年的行情,你想知道的都在这里啦!又一年就这样结束了,各大指数的年线结结实实的走出一根大阴线,上一次年线长阴还是2018年的时候,惨烈的行情总让人记忆犹新,火热的行情又总让人期盼。上证指数年限图今年的行情还需要总结2022年,酒业团体标准大盘点!标准化水平是国家经济社会发展水平的重要标志,是创新发展的引领和推动力量。在人类文明发展史上,从最初度量衡的规范,到工业革命机器零部件的标准化生产,再到现在的ISO认证,标准和标准化
巴萨欧冠落后国米3分!丧失晋级主动权,若想翻盘需看拜仁的脸色足球助力团巴萨vs拜仁欧冠巴萨vs拜仁北京时间2022年10月27日凌晨300,欧冠小组赛C组第5轮,西甲豪门巴萨将在主场迎战德甲班霸拜仁。巴萨本赛季的成绩也有很大提升,主要得益于女孩子真的要嫁给有钱人吗?不一定女孩要嫁给有钱人,如果这个有钱人不疼你不爱你,那他再有钱也不是你的钱。还不如找一个自己爱的人,而且能愿意为你去努力奋斗,给你更好生活的人。女孩子真的要嫁给有钱人吗?每个人的恋网课到底给孩子带来了什么危害?头条创作挑战赛这个问题一直在困扰着各位家长,好像孩子也在学习,为啥学习成绩却在不停下降?飞锅今天来和家长们讲讲这背后的问题所在。大家好我是讲真话的飞锅。现在的小孩子,天天在屋里上网离异家庭对孩子有没有影响单亲家庭的带娃日常离异是多多少少给孩子带来一些负面影响,但是我觉得看大人怎么去正确引导了。我的孩子在刚上小学我就离婚了,在离婚前我就和孩子沟通过这个问题,加上孩子从出生一直我一个人都说笨鸟先飞,可是没有父母扶持的孩子,能飞得起来吗?都说笨鸟先飞,可是没有父母扶持的孩子,能飞得起来吗?我是一个未婚小仙女。无意中见到同事教育孩子的方式,给我带来了难言的感受。大年初七,单位复工,刚进办公室就发现同事带着他儿子腾腾来如何引导孩子勇敢做自己?如何引导孩子勇敢做自己?不仅仅是孩子,我们很多大人,面临各种环境,也往往不敢做自己,死要面子活受罪的例子比比皆是。孩子拥有做自己的勇气,无论什么个性和习惯,都能自我接纳,才能活出真9个计算机的网络层知识点本文分享自华为云社区计算机的网络层究竟有哪些需要学习的?9个知识点看你是否都了解了,作者breakDawn。1。IP地址1。1分类表示法分类表示法已经不常用了。A类地址格式为17位女人啊女人真希望你是个好女人人与人的信任在哪里?人与人的关心和爱护又在哪里,这么久了我也算看透了!两个人在一起不是为了一点小事经常吵架,就是为了钱吵架,甚至有的时候都不知道为了什么突然就吵起来了!如果能后悔我看了这两位70后的经历,才发现50岁后的人生,在劫难逃01hr人生半百之年,那是前一段人生的终点,又是新一段人生的起点。熬过了49岁的中年人,都会特别庆幸,自己能够在人生的考验当中撑了过来。可他们不知道的是,后面的考验,只会越来越难。散文光阴深处,岁月静好,人生诗意安暖作者子墨秋风拂过,盈落一地落叶,是深秋的欢喜,也是岁月薄凉,而我们却依旧拥有着生命中的浅喜深爱。一直以来,我都是喜欢深秋风景的,它给人以安详宁静的感受。凝霜的叶子,火红的枫树,湿润收获一段好时光一缕晨光透过窗,燕子在飞翔,掀开云朵露出光,把前路照亮。我们一起走过最美好的时光。题记最美好的三年,因为有你的陪伴格外精彩。哪怕只是三年,足矣!花开花落,云卷云舒。我们一起经历的快