SVG path 标签根据两点和角度绘制弧线
同步发布:https://blog.jijian.link/2020-04-14/svg-arc/
由于功能受限,此处不能放 iframe 嵌入链接,如需看到实时效果,请移步 https://blog.jijian.link/2020-04-14/svg-arc/
解析
<path> 标签应该算是 SVG 中最为强大的标签了,各种图形都可以用他绘制。
本文使用 path 标签的贝塞尔曲线 Q 指令绘制弧线。
用法
<path d="M30 90 Q115 139 200 90"></path>
<path> 标签常用指令:
- M = moveto
- L = lineto
- H = horizontal lineto
- V = vertical lineto
- C = curveto
- S = smooth curveto
- Q = quadratic Belzier curve
- T = smooth quadratic Belzier curveto
- A = elliptical Arc
- Z = closepath
注释:以上所有命令均允许小写字母。大写表示绝对定位,小写表示相对定位。
绘制线条
常见效果:绘制实线、绘制虚线、绘制弧线、绘制渐变线条、绘制箭头线条。
源码:
<svg width="300" height="300" xmlns="http://www.w3.org/2000/svg"> <defs> <!-- 箭头 --> <marker id="arrow" markerUnits="strokeWidth" markerWidth="12" markerHeight="12" viewBox="0 0 12 12" refX="6" refY="6" orient="auto"> <path d="M2,2 L10,6 L2,10 L6,6 L2,2" style="fill: #000000;"/> </marker> <linearGradient id="line-gradient" x1="0" y1="0" x2="1" y2="0"> <stop offset="0" stop-color="#990000" stop-opacity="0" /> <stop offset="1" stop-color="#990000" stop-opacity="1" /> </linearGradient> </defs> <!-- 实线 --> <path class="line" d="M30 30 L200 30"></path> <!-- 虚线 --> <path class="line" d="M30 60 L200 60" style="stroke-dasharray: 5;"></path> <!-- 弧线 --> <path class="line" d="M30 90 Q115 139 200 90"></path> <!-- 渐变线条 --> <path class="line" d="M30 120 Q115 169 200 120" style="stroke: url(#line-gradient)"></path> <!-- 箭头线条 --> <path class="line" d="M30 150 Q115 199 200 150" style="marker-end:url(#arrow)"></path> <!-- 无浏览器润色的线条,有锯齿像素 --> <path class="line" d="M30 180 Q115 229 200 180" style="shape-rendering: optimizeSpeed;"></path> </svg>
实际应用
实际应用场景不一定会有详细坐标点,需要我们根据已有条件去计算。
比如:已有开始左边和结束坐标,根据这两个坐标绘制一条弧线。
SVG 绘制弧线:
<path d="M30 90 Q115 139 200 90"></path>
M30 90 :表示开始点 x:30 y:90
Q115 139 :表示控制点在 x:115 y:139
200 90 :表示结束点 x:200 y:90
计算控制点图解:
换算为 JS 算法:
const pos = getPosition ({left: 30, top: 90}, {left: 200, top: 90}, 30); console.log(pos); // [{"x":115,"y":139},{"x":115,"y":41}] function getPosition (dot1, dot2, angle) { var x1 = dot1.left; var y1 = dot1.top; var x2 = dot2.left; var y2 = dot2.top; var PI = Math.PI; // 两点间的x轴夹角弧度 var xAngle=Math.atan2((y2-y1), (x2-x1)); // 转为角度 xAngle = 360*xAngle/(2*PI); // 两点间的长度 var L=Math.sqrt((y2-y1)*(y2-y1)+(x2-x1)*(x2-x1)); // 计算等腰三角形斜边长度 var L2 = L/2 / Math.cos(angle* 2*PI/360); // 求第一个顶点坐标,位于下边 var val1={}; // 求第二个顶点坐标,位于上边 var val2={}; val1['x']=x1+Math.round(L2 * Math.cos((xAngle+angle)* 2*PI/360)); val1['y']=y1+Math.round(L2 * Math.sin((xAngle+angle)* 2*PI/360)); val2['x']=x1+Math.round(L2 * Math.cos((xAngle-angle)* 2*PI/360)); val2['y']=y1+Math.round(L2 * Math.sin((xAngle-angle)* 2*PI/360)); return [val1,val2]; }
应用场景:
总结:path 运用远不止此,比如常见的字体图标,SVG 图标等,都可见 path 标签运用,一些炫酷的动画效果也可以使用 path 标签实现。