Javascript动态创建SVG圆弧

0. 起源

需要做一个展示统计数据(百分比)的小部件,默认情况下该小部件是隐藏的。页面右边放置一个圆形的按钮,当点击按钮时小部件从右边滑出显示。

本着尽可能多的展示数据而又不失简约的原则,希望在按钮上展示排名前几名数据的值,这样的话,不必手动点击按钮就知道数据的大概情况,增强了按钮的表现力。通过多个同心圆弧可以做到这一点。

要绘制多个圆弧,可先从绘制一个圆弧着手。

1. 问题描述

先看个草图,如下:

其中,点AAA是圆弧的起点,点O" role="presentation">OOO是圆心,点B是圆弧的终点,θθ \theta 是OBOBOB与OAOAOA的夹角,即 ∠BOA∠BOA \angle{BOA} 。YYY轴的箭头是朝下的,因为SVG使用的是屏幕坐标系。

已知
1. 圆弧起点A" role="presentation">AAA的坐标(startX,startY)(startX,startY)(startX,startY)
2. 圆弧的半径 RRR
3. 圆弧终点B" role="presentation">BBB与起点AAA构成的圆心角θ" role="presentation">θθ\theta,单位为度
4. 圆弧线条的宽度 widthwidthwidth
5. 圆弧线条的颜色 colorcolorcolor

为简化问题,先做一些假设
1. 圆弧起点AAA为圆弧上Y" role="presentation">YYY坐标值最小的点(在屏幕坐标系中)
2. 只按逆时针方向绘制圆弧(起点到终点)


用Javascript动态绘制出符合输入要求的SVG弧形。

2. SVG中的path

SVG中的path元素可以用来绘复杂的图形。它的形状是通过属性d来定义的,属性d的值是”命令+参数”序列。有过在AutoCAD中使用命令来绘图的应该能很快理解。

这里我们只需要用到两个命令:MA命令:

  • M x y
    把画笔移动到点(x,y)(x,y)(x,y) (MMove的缩写)
  • A rx ry x-axis-rotation large-arc-flag sweep-flag x y
    按给定参数绘制圆弧,各部分参数的解释如下:

    • rx ry
      圆弧的xxx轴半径和y" role="presentation">yyy轴半径 A命令也可以用来绘制椭圆弧的,如果是圆弧则 rx=ryrx=ryrx=ry)
    • x-axis-rotation
      xxx轴的旋转角度,这里我们用不到,设为 0
    • large-arc-flag
      是否为大圆弧,1为是,0为否
    • sweep-flag
      圆弧绘制的方向(从起点到终点),1为顺时针,0为逆时针
    • x y
      圆弧终点的坐标(x,y)" role="presentation">(x,y)(x,y)(x,y)

关于图形样式的控制,pathstroke属性用来控制线条的颜色,stroke-width属性用来控制线条宽度,fill属性用来控制线条所包围部分的填充颜色,默认是黑色。

2.1 分析

根据以上对path元素的属性dMA命令的解说,结合第一部分的问题描述,可以有以下分析结果:

  1. M命令来移动到圆弧的起点A(startX,startY)A(startX,startY)A(startX,startY),即 M startX startY
  2. 圆弧的半径rxry可以从已知条件RRR中求得
  3. x" role="presentation">xxx轴的旋转角度 x-axis-rotation,我们不管这个参数,这里设为0
  4. 是否为大圆弧 large-arc-flag 这个参数,我们可以根据θθ\theta这个参数计算得出,如果θ>=180θ>=180\theta>=180,则为大圆弧,反之为小圆弧
  5. 圆弧绘制的方向 sweep-flag问题描述假设部分规定绘制方向为逆时针,所以该值为0
  6. 线条宽度,对应pathstroke-width属性
  7. 线条颜色,对应pathstroke属性
  8. pathfill属性应设为none,即无填充

现在就剩下圆弧的终点坐标 B(x,y)B(x,y)B(x,y) 为未知数了
回忆一下之前学过的平面几何知识,结合问题描述的草图,可得出如下关系式:

{x=cx+Rcos(90+θ)y=cy−Rsin(90+θ)(1)(1){x=cx+Rcos⁡(90+θ)y=cy−Rsin⁡(90+θ)

\begin{equation} \left\{\begin{array}{lr}x = cx + R\cos(90 + \theta) & \\y = cy - R\sin(90 + \theta) \end{array} \right. \end{equation}
为了与已知条件中的角度的单位一致,公式中用的是角度,实际在程序中,需要转换为弧度。可以用如下公式:

α=θ180πα=θ180π

\alpha = \frac{\theta}{180} \pi
其中, αα\alpha是以弧度为单位表示的角度, θθ\theta是以度为单位表示的角度。

2.2 注意点

SVG中,对于圆弧而言,线条的宽度不包含在半径中,线条宽度是向外延伸的。因此在后续参数的计算中需要考虑到这一点,相关参数需要根据线条宽度来调节。

3.编码实现

根据以上分析,编写一个JS函数,生成一个SVGpath元素对象,如下:

function createSVGPath(startX, startY, R, theta, width, color) {var path = document.createElementNS('http://www.w3.org/2000/svg', 'path');var realR = R - width;var dArr = ["M" + startX, startY + width, "A" + realR, realR, 0, theta>=180 ? 1 : 0, 0];var cx = startX, cy = startY + R;var theta2 = theta%360;// 避免360度与0度一样的情况theta = theta > 0 && theta2 == 0 ? 359.9 : theta2;var alpha = (theta + 90)/180 * Math.PI;var dx = realR * Math.cos(alpha);var dy = realR * Math.sin(alpha);var x = cx + dx, y = cy - dy;dArr.push(x.toFixed(2));dArr.push(y.toFixed(2));var d = dArr.join(" ");path.setAttribute('d', d);path.setAttribute('stroke', color);path.setAttribute('stroke-width', width);path.setAttribute('fill', 'none');return path;
}

4. 测试

创建一个html文档,其中包含一个空的svg元素,然后用javascript动态生成一系列圆弧,从360到0度,相邻间隔45度。

源代码如下:

<!DOCTYPE html>
<html>
<head><meta charset="utf8"><title>动态生成SVG圆弧测试</title>
</head>
<body><svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="150px" width="150px" id="svg-01"></svg>
</body>
<script>function createSVGPath(startX, startY, R, theta, width, color) {var path = document.createElementNS('http://www.w3.org/2000/svg', 'path');var realR = R - width;var dArr = ["M" + startX, startY + width, "A" + realR, realR, 0, theta>=180 ? 1 : 0, 0];var cx = startX, cy = startY + R;var theta2 = theta%360;// 避免360度与0度一样的情况theta = theta > 0 && theta2 == 0 ? 359.9 : theta2;var alpha = (theta + 90)/180 * Math.PI;var dx = realR * Math.cos(alpha);var dy = realR * Math.sin(alpha);var x = cx + dx, y = cy - dy;dArr.push(x.toFixed(2));dArr.push(y.toFixed(2));var d = dArr.join(" ");path.setAttribute('d', d);path.setAttribute('stroke', color);path.setAttribute('stroke-width', width);path.setAttribute('fill', 'none');return path;}var svg = document.getElementById('svg-01');var colors = ['red', 'orange', 'yellow', 'green', 'blue', 'cyan', 'purple', 'black'];for(var i=0; i<8; i++){var startY = i*5;var R = 70 - startY;var theta = 360 - 45* i;var path = createSVGPath(75, startY, R, theta, 5, colors[i]);svg.appendChild(path);}
</script>
</html>

效果如下:

Javascript动态创建SVG圆弧相关推荐

  1. javascript动态创建可拖动、最大化、最小化的层

    javascript动态创建可拖动.最大化.最小化的层 2010-02-06 13:19 用Javascript实现div层的拖动是很常见的一种操作,比如弹出提示对话框,快捷登录等等.之前用隐藏层的方 ...

  2. QT通过JavaScript动态创建QML对象

    QT通过JavaScript动态创建QML对象 通过JavaScript动态创建QML对象 动态创建对象 动态创建组件 从QML字符串创建对象 维护动态创建的对象 动态删除对象 通过JavaScrip ...

  3. html表单通过js提交表单提交,JavaScript动态创建form表单并提交的实现方法

    本文实例讲述了JavaScript动态创建form表单并提交的实现方法.分享给大家供大家参考,具体如下: 页面布局有些复杂的情况下,可能需要在页面中动态创建一个 form,JavaScript 创建 ...

  4. javascript动态创建表格:新增、删除行和列

    利用js来动态创建表格有两种格式,appendChild()和insertRow.insertCell().两种方式其实差不多,但第一种有可能在IE上有问题,所以推荐大家使用第二种了,直接说吧. 1. ...

  5. javascript 动态创建表格:新增、删除行和单元格

    2019独角兽企业重金招聘Python工程师标准>>> 利用js来动态创建表格有两种格式,appendChild()和insertRow.insertCell().两种方式其实差不多 ...

  6. 利用javascript动态创建表格

    //说明:实现功能.原理上文相同.不过这次是利用已有的简单的方法创建行和列,并实现内容行鼠标移入变色功能! 效果图: /*两个方法 1.  trNode  table.insertRow(-1)    ...

  7. javascript动态创建radio button元素支持IE/Firefox

    我们都知道在IE中创建表单元素可以有三种方式 var oInput = document.createElement("input"); var oInput = document ...

  8. php动态增加div,JavaScript动态创建div等元素实例

    js动态创建div等元素实例 var Test={ createDiv:function(){ var div = document.createElement('div'); div.id=&quo ...

  9. javascript 动态创建tip图片提示

    前言: 在做前端的项目中,经常看到移动一个小图标上显示这个图标对应的大图的提示,之前的做法是在小图标的位置后面添加一个div,然后移动到小图标然后显示这个图标的图片!但是这个方法做的时候发现,如果提示 ...

最新文章

  1. 100. Leetcode 377. 组合总和 Ⅳ (动态规划-完全背包)
  2. 多线程:Executor、Sleep、Deamon、Yeild
  3. UI组件之TextView及其子类(一)TextView和EditText
  4. php7协程通信使用,PHP7下的协程实现
  5. (素材源代码) 猫猫学iOS 之UIDynamic重力、弹性碰撞吸附等现象牛逼Demo
  6. linux服务器时间不同步解决方法
  7. 那些年开发中遇到的坑。。。
  8. AOP处理事务静、动态代理(jdk方法)
  9. node.js下mongoose简单操作实例
  10. 解决sklearn库使用过程中No module named model_selection的错误
  11. cx_Oracle库导入失败引起crontab中python程序运行失败,并且无错误提示
  12. 平面波角谱积分 matlab,第2章2_5平面波角谱.ppt
  13. Redux:优点和缺点
  14. 写给0-3岁产品经理的第1封信:《产品经理的经济基础——逻辑思维能力》
  15. Pyinstaller:moviepy打包报错AttributeError: module ‘moviepy.audio.fx.all‘ has no attribute ‘audio_fadein‘
  16. 为 Form Library 开发工作流,如何读取 InfoPath 表单内容
  17. 微信定时向好友发信息(循环发信息)
  18. 浅聊前端程序员,后端程序员,全栈程序员的工作
  19. 重卡自动驾驶进入“正规战”
  20. 小米装linux双系统,小米9双系统发布

热门文章

  1. [附源码]Node.js计算机毕业设计大学生健康管理系统的设计与实现Express
  2. ubuntu设置共享文件夹
  3. Visual Studio 2010安装、配置及使用
  4. SAP PP配置详解之五:生产计划编制
  5. 为何亚马逊的中国电商之路以失败收场?当当网创始人这样说
  6. Redis Geospatial地理位置
  7. MHT: Basic Methods for Data Association(二)Track Score Function
  8. 代码随想录贪心算法——买卖股票的最佳时机含手续费
  9. maya拆完uv,画好贴图后导入,模型上贴图显示混乱
  10. leetcode--给房子涂色III