00、前端图形
前端代码实现图形的几种方式:CSS、SVG、Canvas(主要是JavaScript编码)
CSS也是可以画图的,需要借助于高宽、边框border、clip-path裁剪、渐变色背景等属性来模拟实现各种图形,当然只能实现一些简单的图形。
border:用四条边框样式属性的各种组合变换,实现一些简单的图形。网上也有画一些稍微复杂的图形,如哆啦A梦,但代码量稍多,可读性不好,并不推荐。
<div class="gcss"><p class="border">border</p><p class="rborder">圆角按钮</p><p class="radio"></p>radio<p class="triangle1"></p>三角形<p class="triangle2"></p>三角形</div><style>.gcss p {display: inline-block;text-align: center; vertical-align: middle;}.border {border: 30px solid;border-color: aqua tan violet peru;border-radius: 20px;}.rborder {background-color: #b1ccf3;width: 100px; height: 40px; line-height: 40px;border-radius: 20px;}.radio {width: 40px; height: 40px;border-radius: 50%;border: 10px solid;}.triangle1 {border: 50px solid #0001;border-left-color: red;}.triangle2 {border-left: 50px solid #0001;border-right: 50px solid #0001;border-bottom: 50px solid red;}</style>

01、
可缩放矢量图形(Scalable Vector Graphics,SVG),是一种基于 XML(数学)描述的二维的矢量图形,内容可以直接插入网页,成为DOM的一部分,然后用 JavaScript 和 CSS 进行操作。SVG 内容也可以写在一个独立文件中,然后用CSS(background-url)、<img>、<object>、<embed>、<iframe>来引用。
大多数现代浏览器都支持SVG 图形,越来越多的项目在使用SVG图形,简单的像图标,复杂的一些图表Chart也有不少是基于SVG实现的。相比于位图,体积更小,可无线缩放而不失真。
| 比较 | 矢量图形 | 位图 |
|---|---|---|
| 存储的数据 | 存储元素、算法数据 | 存储像素数据 |
| 存储大小 | 小 | 大 |
| 缩放效果 | 无线缩放,不失真 | 固定大小,放大会失真 |
| 可维护性 | 很容易修改 | 修改麻烦 |
| 扩展性 | 支持CSS、JS | 不支持 |
| 文件格式 | .svg,直接嵌入数据到页面 |
.bmp/.png/.jpg/.gif, |
| 支持的元素 | <svg>、<img>、<iframe>、<object> |
<img>、<iframe> |
| 兼容性 | IE9开始支持 | 较好 |
| 渲染性能 | 复杂的SVG会占用很多时间 | 稳定 |
| 网络传输性能 | 和页面数据一起,体积小,速度快 | 需单独请求图片资源 |
| 缓存 | 随网页内容一起,不可单独缓存 | 图片可单独缓存 |
1.1、<svg>元素
<svg>内部支持多种图形算法,基础的如线line、圆形<circle>、矩形rect、文本text,复杂的有折线polyline、多边形polygon、路径数据path等。这些图形都以子元素的形式组合,因此也就都支持CSS、JS的操作了。iconfont-阿里巴巴矢量图标库上有非常丰富的
| 元素/属性 | 描述 | 值/示例 |
|---|---|---|
| 矢量图形元素 | ||
| viewBox | SVG 画布显示区域,这里 1 单位等同于 1 屏幕单位,SVG里的坐标、尺寸都是基于此画布区域 | viewBox="0 0 300 200" |
| width、height | 宽度、高度 | width="300" height="200" |
| xmlns | xml标签的命名空间,为了区分html、svg,可以省略 | |
| 线段 | ||
| x1、y1 | 起点x、y坐标 | <line x1="0" y1="100" /> |
| x2、y2 | 终点x、y坐标 | x2="300" y2="100" |
矩形:<rect x="5" y="50" height="100" width="290"/> |
||
| x、y | 起点坐标 | |
| width、height | 矩形的宽、高 | |
| rx、ry | x、y方向的圆角半径。r=radius 半径 | rx="50" ry="50" |
圆和椭圆:<circle cx="150" cy="100" r="80"/> |
||
| cx、cy | 圆心的x、y坐标 | |
| r | 圆的半径长度 | |
| rx、ry | 椭圆的x、y半径 | |
| [polyline](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/polyline)/[polygon](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/polygon) | 折线、多边形,两者数据结构相似,多边形是自动首尾连接封闭成一个区域(Polygon /ˈpɒlɪɡən/ 多边形) | |
| points | x、y坐标的集合,多个坐标逗号,分割 |
points="0 0, 20 40, 70 80/> |
路径,很常用、很强大的图形绘制,数据在属性d中 |
||
| 路径数据, |
d="M 50 5 H250 V195 H50 Z" |
|
| M x y | 移动画笔到坐标点x、y | M50 5 |
| L x y | 划线到坐标x、y | L 250 0 |
| H x | 绘制水平线,到坐标x;小写h的坐标为相对位置 |
H 250 |
| V y | 绘制垂直线,到坐标y;小写v的坐标为相对位置 |
V195 |
| Z | 闭合路径(closepath),放到最后用于闭合路径 | |
| C* | 绘制曲线,包括贝塞尔曲线、圆弧。 | |
| <text> | 文本标签,支持CSS样式中的文本样式 | |
| x、y | 文本开始位置 | |
| font-size | 字体大小 | |
| 文字绘制的路径,这个就比较有趣了 | <textPath xlink:href="#path1"> |
|
| 公共属性 | 部分属性可以用CSS设置,支持hover伪类 | |
| stroke | 笔画颜色(stroke /stroʊk/ 笔画) ,包括线段、形状线条。 | stroke="red" |
| stroke-width | 画笔线宽 | stroke-width="10" |
| fill | 填充颜色,填充一个区域(矩形、圆形等) | fill="#0001" |
:::warning ❗小提示:注意服务器添加对svg的支持,及gzip压缩。 :::
<svg version="1.1" baseProfile="full" width="300" height="200" xmlns="http://www.w3.org/2000/svg"><circle cx="150" cy="100" r="80" fill="green" /><circle cx="150" cy="100" r="70" fill="#fff" /><text x="150" y="125" font-size="60" text-anchor="middle" fill="orange">SVG</text><line x1="0" y1="100" x2="300" y2="100" stroke="white" stroke-width="8"/></svg><svg class="icon" height="200" viewBox="0 0 300 200" version="1.1"><rect x="5" y="50" rx="50" ry="50" height="100" width="290" fill="white" stroke="blue" stroke-width="10"/><path d="M 50 5 H250 V195 H50 Z" stroke="red" stroke-width="10" fill="#00000001" /><text x="145" y="125" font-size="60" text-anchor="middle" fill="#fab">Path</text></svg><style>svg:hover{background-color: aliceblue;stroke: red;stroke-width: 1px;fill: red;}</style>
1.2、动画
SVG 本身就是一个HTML元素,因此动画可以用CSS的动画来实现(参考 CSS动画),SVG中也有专门用于实现动画的<animate>子元素。这里示例采用JavaScript+transform变换实现旋转效果。
<svg version="1.1" baseProfile="full" width="300" height="200" xmlns="http://www.w3.org/2000/svg"><circle cx="150" cy="100" r="80" fill="green" /><circle cx="150" cy="100" r="70" fill="#fff" /><text class="svgc" x="150" y="125" font-size="60" text-anchor="middle" fill="orange" >SVG</text><line class="svgc" x1="0" y1="100" x2="300" y2="100" stroke="white" stroke-width="8" /></svg><script>let svgcs = document.querySelectorAll(".svgc");//设置中心点svgcs.forEach(element => {element.setAttribute("transform-origin", '150 100');});let deg = 0;setInterval(() => {deg = deg > 360 ? 0 : deg+4;svgcs.forEach(element => {element.setAttribute("transform", `rotate(${deg})`);});}, 100);</script><!-- 用CSS动画实现的版本 --><style>.svgc {transform-origin: 150px 100px;animation: svgc-routate 2s linear 1s infinite;}@keyframes svgc-routate {from {transform: rotate(0deg);}to {transform: rotate(360deg);}}</style>
1.3、svg工具/资源/库
🔸矢量图标资源
- Iconfont-阿里巴巴矢量图标库,功能很强大,及其提供丰富的矢量图标库,提供矢量图标下载、在线存储、格式转换等功能。应该就这个就够了!
flaticon,国外的矢量图标库
🔸SVG工具
路径
可以绘制任意的图形,直接编码是比较困难的,特别是 C贝塞尔曲线。所以一般都是用专业工具来绘制专业工具AI:Adobe Illustrator
- 在线SVG编辑器,Method Draw
SVGator,一个在线SVG动画制作工具,导入SVG文件,进行可视化的动画制作。
🔸动画库
第三方库GSAP,来自GreenSock,可以更简单的实现更丰富的动画效果,不光支持SVG,包括页面中任意可以通过JS访问的元素、属性,都可以实现动画。
- anime.js,功能强大,非常轻量,压缩后大小9K。
- SVG动画库:mo.js、SVG.js
02、
只是一块平平无奇的画布而已(在HTML中就一个<canvas>元素),提供了一点点API,由JS进行绘制各种图形。2D的canvas绘制和<SVG>挺像,都是一些线、矩形、圆、path路径数据。这里就先简单了解一下,<canvas>功能是很强大的,很多可视化图表都是基于<canvas>实现的。
🔸基本特点:
- 双标签,必须包含闭合标签。标签内可以放提示文字,当浏览器不支持
<canvas>会显示。 - 坐标系以左上角为中心点,和SVG一样。

- MDN:Canvas 教程
2.1、canvas API
| canvas 属性/方法 | 描述 | | —- | —- | | height、width | 元素高度、宽度:<canvas width="400" height="400"></canvas>| | getContext(contextType) | 获取用于绘制的渲染上下文,contextType:
- “2d”:CanvasRenderingContext2D 二维渲染上下文
- “webgl”: WebGLRenderingContext 三维渲染上下文,OpenGL ES 2.0
- “webgl2”:WebGL2RenderingContext 三维渲染上下文,OpenGL ES 3.0
| | CanvasRenderingContext2D | | | fillStyle | 填充(内部)颜色ctx.fillStyle='rgba(250,0,0,0.6)'| | strokeStyle | 画笔(边框)颜色ctx.strokeStyle='red',同上,支持color、渐变色画刷、图片画刷 | | font | 字体设置ctx.font = "bold 48px serif"| | lineWidth | 线宽ctx.lineWidth = 15;| | toDataURL(type, quality) | 可以将canvas绘制的图形转换为Data URI 格式的图像,从而导出为位图文件 | | 基础图形绘制 |
| | fillRect(x, y, width, height) | 填充一个矩形 | | strokeRect(x, y, width, height) | 绘制一个矩形框 | | clearRect(x, y, width, height) | 清除指定区域的的像素 | | fillText(text, x, y, [maxWidth]) | 填充文本 | | strokeText(text, x, y [, maxWidth]) | 绘制文本(轮廓) | | drawImage() | 绘制位图 | | 路径绘制 | ①创建路径 > ②创建路径 > ③渲染路径 | | beginPath() | 开始一个新的路径,清除已有路径列表 | | closePath() | 闭合一个路径 | | moveTo(x, y) | 移动画笔到坐标x、y | | lineTo(x, y) | 画线到坐标x、y | | ellipse(x, y, radiusX, radiusY,r,sa,ea) | 椭圆路径ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle)| | rect(x, y, width, height) | 矩形路径 | | arc(x, y, radius, startAngle, endAngle) | 绘制圆弧路径 | | quadraticCurveTo(cp1x, cp1y, x, y) | 二次贝塞尔曲线 | | fill([path], [fillRule]) | 填充当前、已存在的路径 | | stroke([path]) | 描边子路径 | | Path2D | 可以单独申明一个路径对象,支持上面的绘制,还支持SVG的path数据。 |
<canvas id="canvas" width="400" height="400"></canvas><script>ctx = document.getElementById('canvas').getContext('2d');// ctx.alpha = false;ctx.fillStyle = 'rgba(250,0,0,0.6)';ctx.fillRect(10, 10, 40, 40);ctx.fillRect(30, 30, 40, 40);ctx.strokeStyle = 'red';ctx.lineWidth = 3;ctx.strokeRect(90, 10, 150, 50);ctx.fillStyle = 'rgba(0,0,250,0.5)';ctx.font = '20px 微软雅黑';ctx.fillText("文本Text", 120, 40)//pathctx.beginPath();ctx.moveTo(90, 80);ctx.lineTo(90, 200);ctx.lineTo(190, 200);ctx.closePath();ctx.arc(120, 120, 50, 0, 360);ctx.fill();</script>

- 二次贝塞尔曲线调试器
- 三次贝塞尔曲线调试器
:::info
弧度 = ( Math.PI / 180 ) 角度,360度的弧度= Math.PI2
:::
2.2、动画
Canvas的动画就是不停的重绘,其实任何动画都是这样,前端实现动画有以下几种姿势:
- setInterval(function, delay):定时重绘,适合不需要交互的场景。
- setTimeout(function, delay):定时重绘,适合通过键盘或者鼠标事件来捕捉用户的交互,再用
setTimeout执行相应的动作。 - requestAnimationFrame(callback):动画专用API,这个方法更加平缓并更加有效率,当系统准备好了重绘条件的时候,才调用绘制动画帧。
:::warning
**requestAnimationFrame**(render)是HTML5提供的动画API,他向浏览器申请执行一个动画帧渲染函数,浏览器在下次重绘(刷新)之前调用这个render回调函数。requestAnimationFrame还做了很多优化以提升性能和流畅度。 :::
- 稳定60帧:浏览器的刷新周期大多和屏幕刷新率匹配,为每秒60次,非常稳定高效。不像
setInterval、setTimeout还要在任务队列里排队等待,就可能发生丢帧和卡顿现象。 - 合并优化:浏览器会优化动画的执行,把每一帧的所有DOM操作集中起来,在一个渲染周期内执行。
- 隐藏优化:当前窗口或者标签页不可见时停止运行
requestAnimationFrame。<canvas id="canvas" width="400" height="400"></canvas><script>ctx = document.getElementById('canvas').getContext('2d');//动画旋转let eangle = 0;function drawEllipse() {ctx.clearRect(255, 150, 140, 140);ctx.beginPath();ctx.fillStyle = 'rgba(0,250,0,0.3)';eangle = eangle > 360 ? 0 : eangle + 1;ctx.ellipse(320, 230, 60, 30, eangle * Math.PI / 180, 0, 2 * Math.PI);ctx.stroke();ctx.fill();ctx.beginPath();ctx.ellipse(320, 230, 30, 60, eangle * Math.PI / 180, 0, 2 * Math.PI);ctx.fillStyle = 'rgba(0,0,250,0.3)';ctx.stroke();ctx.fill();}setInterval(drawEllipse, 20);//水平移动let lx = 40;let ltr = true;function drawRect() {if (lx > 300) ltr = false;if (lx < 40) ltr = true;// ctx.clearRect(lx, 220, 40, 40);ctx.fillStyle = 'rgb(255,255,255,0.4)';ctx.fillRect(20, 290, 340, 60);lx = ltr ? lx + 2 : lx - 2;ctx.fillStyle = 'rgb(110,22,250)';ctx.fillRect(lx, 300, 40, 40);ctx.strokeRect(lx, 300, 40, 40);requestAnimationFrame(drawRect); //永远不停的提交渲染申请,递归自己}requestAnimationFrame(drawRect);</script>

用canvas实现的一个彩球大战:codepen
03、WebGL
WebGL 作为一种WEB 3D绘图技术,依托于<canvas>元素。WebGL是运行在GPU上的,可面向底层显卡编程,可调用底层的接口,实现硬件加速,在2D图形绘制上性能会优于Canvas2D。
传说原生的WebGL比较难学,可考虑使用使用第三方的WebGL库,如Three.js、Cesium.js(3D地图)、Babylon.js
MDN:WebGL 教程
©️版权申明:版权所有@安木夕,本文内容仅供学习,欢迎指正、交流,转载请注明出处!原文编辑地址
