00、前端图形

前端代码实现图形的几种方式:CSS、SVG、Canvas(主要是JavaScript编码)
前端图形:SVG与Canvas - 图1
CSS也是可以画图的,需要借助于高宽、边框borderclip-path裁剪、渐变色背景等属性来模拟实现各种图形,当然只能实现一些简单的图形。
border:用四条边框样式属性的各种组合变换,实现一些简单的图形。网上也有画一些稍微复杂的图形,如哆啦A梦,但代码量稍多,可读性不好,并不推荐。

  1. <div class="gcss">
  2. <p class="border">border</p>
  3. <p class="rborder">圆角按钮</p>
  4. <p class="radio"></p>radio
  5. <p class="triangle1"></p>三角形
  6. <p class="triangle2"></p>三角形
  7. </div>
  8. <style>
  9. .gcss p {
  10. display: inline-block;
  11. text-align: center; vertical-align: middle;
  12. }
  13. .border {
  14. border: 30px solid;
  15. border-color: aqua tan violet peru;
  16. border-radius: 20px;
  17. }
  18. .rborder {
  19. background-color: #b1ccf3;
  20. width: 100px; height: 40px; line-height: 40px;
  21. border-radius: 20px;
  22. }
  23. .radio {
  24. width: 40px; height: 40px;
  25. border-radius: 50%;
  26. border: 10px solid;
  27. }
  28. .triangle1 {
  29. border: 50px solid #0001;
  30. border-left-color: red;
  31. }
  32. .triangle2 {
  33. border-left: 50px solid #0001;
  34. border-right: 50px solid #0001;
  35. border-bottom: 50px solid red;
  36. }
  37. </style>

image.png


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与Canvas - 图3可嵌入svg文件
支持的元素 <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压缩。 :::

  1. <svg version="1.1" baseProfile="full" width="300" height="200" xmlns="http://www.w3.org/2000/svg">
  2. <circle cx="150" cy="100" r="80" fill="green" />
  3. <circle cx="150" cy="100" r="70" fill="#fff" />
  4. <text x="150" y="125" font-size="60" text-anchor="middle" fill="orange">SVG</text>
  5. <line x1="0" y1="100" x2="300" y2="100" stroke="white" stroke-width="8"/>
  6. </svg>
  7. <svg class="icon" height="200" viewBox="0 0 300 200" version="1.1">
  8. <rect x="5" y="50" rx="50" ry="50" height="100" width="290" fill="white" stroke="blue" stroke-width="10"/>
  9. <path d="M 50 5 H250 V195 H50 Z" stroke="red" stroke-width="10" fill="#00000001" />
  10. <text x="145" y="125" font-size="60" text-anchor="middle" fill="#fab">Path</text>
  11. </svg>
  12. <style>
  13. svg:hover{
  14. background-color: aliceblue;
  15. stroke: red;
  16. stroke-width: 1px;
  17. fill: red;
  18. }
  19. </style>

image.png

1.2、动画

SVG 本身就是一个HTML元素,因此动画可以用CSS的动画来实现(参考 CSS动画),SVG中也有专门用于实现动画的<animate>子元素。这里示例采用JavaScript+transform变换实现旋转效果。

  1. <svg version="1.1" baseProfile="full" width="300" height="200" xmlns="http://www.w3.org/2000/svg">
  2. <circle cx="150" cy="100" r="80" fill="green" />
  3. <circle cx="150" cy="100" r="70" fill="#fff" />
  4. <text class="svgc" x="150" y="125" font-size="60" text-anchor="middle" fill="orange" >SVG</text>
  5. <line class="svgc" x1="0" y1="100" x2="300" y2="100" stroke="white" stroke-width="8" />
  6. </svg>
  7. <script>
  8. let svgcs = document.querySelectorAll(".svgc");
  9. //设置中心点
  10. svgcs.forEach(element => {
  11. element.setAttribute("transform-origin", '150 100');
  12. });
  13. let deg = 0;
  14. setInterval(() => {
  15. deg = deg > 360 ? 0 : deg+4;
  16. svgcs.forEach(element => {
  17. element.setAttribute("transform", `rotate(${deg})`);
  18. });
  19. }, 100);
  20. </script>
  21. <!-- 用CSS动画实现的版本 -->
  22. <style>
  23. .svgc {
  24. transform-origin: 150px 100px;
  25. animation: svgc-routate 2s linear 1s infinite;
  26. }
  27. @keyframes svgc-routate {
  28. from {
  29. transform: rotate(0deg);
  30. }
  31. to {
  32. transform: rotate(360deg);
  33. }
  34. }
  35. </style>

1.gif

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.jsSVG.js

02、基础

只是一块平平无奇的画布而已(在HTML中就一个<canvas>元素),提供了一点点API,由JS进行绘制各种图形。2D的canvas绘制和<SVG>挺像,都是一些线、矩形、圆、path路径数据。这里就先简单了解一下,<canvas>功能是很强大的,很多可视化图表都是基于<canvas>实现的。
🔸基本特点

  • 双标签,必须包含闭合标签。标签内可以放提示文字,当浏览器不支持<canvas>会显示。
  • 坐标系以左上角为中心点,和SVG一样。

前端图形:SVG与Canvas - 图6

  • 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数据。 |
  1. <canvas id="canvas" width="400" height="400"></canvas>
  2. <script>
  3. ctx = document.getElementById('canvas').getContext('2d');
  4. // ctx.alpha = false;
  5. ctx.fillStyle = 'rgba(250,0,0,0.6)';
  6. ctx.fillRect(10, 10, 40, 40);
  7. ctx.fillRect(30, 30, 40, 40);
  8. ctx.strokeStyle = 'red';
  9. ctx.lineWidth = 3;
  10. ctx.strokeRect(90, 10, 150, 50);
  11. ctx.fillStyle = 'rgba(0,0,250,0.5)';
  12. ctx.font = '20px 微软雅黑';
  13. ctx.fillText("文本Text", 120, 40)
  14. //path
  15. ctx.beginPath();
  16. ctx.moveTo(90, 80);
  17. ctx.lineTo(90, 200);
  18. ctx.lineTo(190, 200);
  19. ctx.closePath();
  20. ctx.arc(120, 120, 50, 0, 360);
  21. ctx.fill();
  22. </script>

image.png

  1. setInterval(function, delay):定时重绘,适合不需要交互的场景。
  2. setTimeout(function, delay):定时重绘,适合通过键盘或者鼠标事件来捕捉用户的交互,再用 setTimeout执行相应的动作。
  3. requestAnimationFrame(callback):动画专用API,这个方法更加平缓并更加有效率,当系统准备好了重绘条件的时候,才调用绘制动画帧。 :::warning **requestAnimationFrame**(render)是HTML5提供的动画API,他向浏览器申请执行一个动画帧渲染函数,浏览器在下次重绘(刷新)之前调用这个render回调函数。requestAnimationFrame还做了很多优化以提升性能和流畅度。 :::
  • 稳定60帧:浏览器的刷新周期大多和屏幕刷新率匹配,为每秒60次,非常稳定高效。不像setIntervalsetTimeout还要在任务队列里排队等待,就可能发生丢帧和卡顿现象。
  • 合并优化:浏览器会优化动画的执行,把每一帧的所有DOM操作集中起来,在一个渲染周期内执行。
  • 隐藏优化:当前窗口或者标签页不可见时停止运行requestAnimationFrame
    1. <canvas id="canvas" width="400" height="400"></canvas>
    2. <script>
    3. ctx = document.getElementById('canvas').getContext('2d');
    4. //动画旋转
    5. let eangle = 0;
    6. function drawEllipse() {
    7. ctx.clearRect(255, 150, 140, 140);
    8. ctx.beginPath();
    9. ctx.fillStyle = 'rgba(0,250,0,0.3)';
    10. eangle = eangle > 360 ? 0 : eangle + 1;
    11. ctx.ellipse(320, 230, 60, 30, eangle * Math.PI / 180, 0, 2 * Math.PI);
    12. ctx.stroke();
    13. ctx.fill();
    14. ctx.beginPath();
    15. ctx.ellipse(320, 230, 30, 60, eangle * Math.PI / 180, 0, 2 * Math.PI);
    16. ctx.fillStyle = 'rgba(0,0,250,0.3)';
    17. ctx.stroke();
    18. ctx.fill();
    19. }
    20. setInterval(drawEllipse, 20);
    21. //水平移动
    22. let lx = 40;
    23. let ltr = true;
    24. function drawRect() {
    25. if (lx > 300) ltr = false;
    26. if (lx < 40) ltr = true;
    27. // ctx.clearRect(lx, 220, 40, 40);
    28. ctx.fillStyle = 'rgb(255,255,255,0.4)';
    29. ctx.fillRect(20, 290, 340, 60);
    30. lx = ltr ? lx + 2 : lx - 2;
    31. ctx.fillStyle = 'rgb(110,22,250)';
    32. ctx.fillRect(lx, 300, 40, 40);
    33. ctx.strokeRect(lx, 300, 40, 40);
    34. requestAnimationFrame(drawRect); //永远不停的提交渲染申请,递归自己
    35. }
    36. requestAnimationFrame(drawRect);
    37. </script>
    1.gif
    用canvas实现的一个彩球大战:codepen

03、WebGL

WebGL 作为一种WEB 3D绘图技术,依托于<canvas>元素。WebGL是运行在GPU上的,可面向底层显卡编程,可调用底层的接口,实现硬件加速,在2D图形绘制上性能会优于Canvas2D。
传说原生的WebGL比较难学,可考虑使用使用第三方的WebGL库,如Three.js、Cesium.js(3D地图)、Babylon.js
MDN:WebGL 教程


©️版权申明:版权所有@安木夕,本文内容仅供学习,欢迎指正、交流,转载请注明出处!原文编辑地址