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

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

WebRTC音频引擎实现分析WebRTC的音频引擎作为两大基础多媒体引擎之一,实现了音频数据的采集前处理编码发送接收解码混音后处理播放等一系列处理流程。本文在深入分析WebRTC源代码的基础上,学习并总结其音感染之后咳嗽不止,这些止咳小妙招总有适合你的一食疗法1梨子汤,梨子红枣冰糖加枸杞(可不加)加适量水煮沸。2盐蒸橙子,将橙子切开口,用牙签戳数洞,撒上少许盐,上锅蒸熟。二耳穴压豆取穴鼻咽喉气管肺肾脾肾上腺皮质下咳喘点。每次取一男子在梵净山金顶摩崖刻4字被判赔12万,二审维持原判新时代推动法治进程,2022年度十大案件候选案例中,包括一起针对生态破坏的公益诉讼案。在这起案件中,当事人在梵净山景区文物上刻字,被当地检察机关提起公益诉讼。一段拍摄于2021年7绿色林海的别样风景闪耀在庐山之巅的火焰蓝今年的庐山有一道别致的风景,在茫茫的绿色林海中,一群阳光帅气的蓝朋友在庐山周边执行森林防火执勤任务。2022年12月10日,内蒙古森林消防总队派出了内蒙古大兴安岭森林消防支队30015条精品线路发布!你去过哪些?为贯彻落实大运河文化带建设工作部署,积极促进水利风景资源保护利用,助力全省幸福河湖建设,近日,江苏省水利厅遴选推出故道千里远,故事千年传等15条水利风景区精品线路,串联全省76家特临汾黄河一号旅游公路主线实现贯通1月3日,山西晚报记者从临汾市交通运输局了解到随着黄河一号旅游公路主线吉县境内大宁界至姚家畔段冯家庄大桥近日完成架设,该市黄河一号旅游公路主线实现全线贯通。临汾市黄河一号旅游公路主江苏出土汉代双龙墓,开棺后竟冒出一条大白腿,专家看后毛骨悚然江苏连云港惊现千年不腐女尸,专家挖到一半时仓皇而逃一座古墓诉说千年传说,一段传说传承古今历史。2002年的炎炎盛夏,江苏连云港一村庄正在修建高速公路,工人们挖到了一块木板,细细一看元旦经济堂食小高峰出现,部分餐厅客流同比政策优化前增长1300随着全国防疫政策的优化以及稳增长促消费等政策信号释放,2023年元旦假期内,不少餐饮品牌的客流增长超预期,全国多店恢复排长队的热闹场景。不断刷新的叫号提示是餐饮消费加速回暖的缩影。又要囤药?这种药品家里有孩子的禁用,小心吃了之后不长个冬日生活打卡季随着疫情的精准调控实施,国人们已经感受到了它的威力。尤其是在彻底放开之后,更是让越来越多的人都确诊了阳性。感染后,会出现发烧咳嗽等症状,而随着病毒的变异,新的症状也陆揭秘!人工授精实验室如何挑选精兵强将人工授精是一种人工辅助生殖技术,是将优化后的精子注射入女性的生殖道内或宫腔内,达到受孕的目的。人工授精主要适用于男方勃起性功能障碍严重早泄轻中度的少弱精子症免疫性不育女方宫颈因素及怀孕5周的媳妇阳了后胎停流产了中心妇产医院,张明宇陪着媳妇王敏来到计划生育科做孕检,看看孩子的发育状态怎么样。两人高高兴兴地一边办理手续,一边打趣孩子会像谁。随后王敏进入候诊区等待,张明宇则满怀希望的在外面等候
白皮书中国致力于促进互联网发展成果惠及不同国家和地区人民新华社北京11月7日电国务院新闻办公室7日发布的携手构建网络空间命运共同体白皮书指出,中国坚持以人为本科技向善,积极响应国际社会需求,共同致力于弥合数字鸿沟,推动网络文化交流与文明全球展商齐聚进博会这是中国对外开放的标志,也是对抗逆全球化的平台文观察者网王恺雯编辑周远方11月5日至10日,全球展商齐聚上海,再次迎来进博时刻。全球首发亚洲首秀中国首展,举办五年来,进博会已经成为全球新产品新技术进入中国市场的重要窗口。与此同腾讯WiFi管家12月1日起,停止服务近日,腾讯WiFi管家发布公告称,因业务调整,腾讯WiFi管家将于2022年12月1日零时零分起正式停止服务。届时用户将无法使用腾讯WiFi管家的任何功能和服务。在停止服务后,腾讯张益唐夫人谈丈夫轶事从早到晚搞研究,晚上炒菜分散注意力近日,著名华裔数学家张益唐关于朗道西格尔零点猜想的学术突破,引起国内公众持续关注。11月5日,他参加了山东大学举行的线上学术讲座与学术沙龙,介绍自己向证明朗道西格尔零点不存在做出的日均亏2。6亿!三大航三季度净亏241亿,亏损金额已超去年全年中国经济周刊记者贾璇近日,4969家上市公司先后完成了2022年第三季度的财报披露。其中,三大航司业绩环比发生好转,但仍未走出巨亏阴霾,分别现身单季亏损榜单。这也预示着,今年航空业宝新能源收监管函近三年董监高薪酬事项审议程序不完善离任董事去年酬劳超3000万每经记者吴泽鹏每经编辑杨夏11月7日,宝新能源(SZ000690,股价5。42元,市值117。9亿元)收到深交所下发的监管函,事因在2019年2021年期间,该公司有关董事(不含独过年带狗狗爬山,主人要是没有准备好,等下得把它抱下山过年总算有假期,主人总想带着狗狗出去外面玩儿。但不少景区都不能带狗,带狗游玩最热门的项目,就是带它们去爬山。但爬上也要有所准备,不然可能会给主人惹不少麻烦。就像前几年有个主人带着巨2023年养老金有望19连涨,但这6类人享受不到,包括你在内吗?11月财经新势力养老金是退休人员唯一的经济来源,每年只能寄希望于养老金上调来提升待遇,截止2022年养老金已经实现了18连涨。如今老人们最关心的话题莫过于2023年养老金能否继续上上周五人民币汇率大反弹今日人民币中间价上调263基点11月7日,人民币对美元汇率中间价报7。2292,上调263点,上一交易日中间价报7。255。上周最后一个交易日,离岸在岸人民币双双大涨。11月4日,更多反映国际投资者预期的离岸人金税四对普通人的影响越来越紧的步伐和政策的实施,关乎到我们每一个人的又一项大政策,金税四终于要落地了。在信息化高度发达的现在,金税四的落地也是必然。目前顶层设计已经完成,所有第三方账户的税务将被全面核美国中期选举结果前瞻与市场影响事件北京时间11月8日,美国将迎来国会中期选举投票日。核心结论11月8日将迎来美国中期选举投票日,本篇报告主要分析了本次选举最核心的三个问题可能的结果结果确定时间对市场的影响。1目