Open YIXUNFE opened 8 years ago
近期项目中有一个环形图的需求,经过大家研究后决定使用一款开源插件完成。选用插件主要是考虑到需要兼容 IE678,而目前我们团队中没人熟悉 VML。但是这里我仅简单介绍下我们完成的 N 个实验性方案中的一个 —— 使用 stroke-dasharray 制作环形图。
stroke-dasharray
以前在《玩转虚线边框》的文章中提及过,SVG 元素可以通过 stroke-dasharray 设置虚线边框的长度以及虚线之间的宽度。所以我们只需要通过圆形的路径,使用虚线长度表述所占百分比即可。
比如环状图中有 4 个区域,每个区域各占 25%,那么每个区域应该设置虚线长度为周长的 25%,虚线与虚线之间的间距应该是周长的 75%。
我们可以使用 circle 元素画圆,并指定它的圆心与半径。由于我们最终需要的是圆环,那么我们也需要给圆形指定边宽 stroke-width。
circle
stroke-width
<circle cx="200" cy="200" r="120" stroke-width="80" stroke="#ff0000" fill="none" ></circle>
加上 stroke-dasharray 之后:
<circle cx="200" cy="200" r="120" stroke-width="80" stroke="#ff0000" fill="none" stroke-dasharray="189 566" ></circle>
stroke-dasharray 的两个值,一个表示虚线的长度,另一个表示虚线与虚线之间的间距,而间距之间是一片空白,所以图形从圆变成了圆弧。然而这好像和我们想象中的有点不一样,我们希望它是从右上方开始的。所以我们需要转换一下坐标系。
<circle cx="200" cy="200" r="120" stroke-width="80" stroke="#ff0000" fill="none" stroke-dasharray="189 566" transform="rotate(-90, 200, 200)" ></circle>
设置 transform 的 rotate 属性,里面的三个参数分别表示旋转的角度、旋转中心的 X 轴坐标,旋转中心的 Y 轴坐标。这里旋转中心就是我们的圆心。
transform
rotate
这样我们就完成了第一个区域的制作。接下来我们制作第二个区域。第二个区域的圆弧起始位置应该在第一个圆弧的结束位置,即 0 度处(-90 + 360 * 0.25)。
<circle cx="200" cy="200" r="120" stroke-width="80" stroke="#ffff00" fill="none" stroke-dasharray="189 566" transform="rotate(0, 200, 200)" ></circle>
以此类推,我们就可以完成整个环状图的构建工作。
为了能够更加方便的绘制环状图,我们抽象出了一个方法。
/** * createArcs * @param {Object} args 配置项 * @example createArcs({ bin: div, width: 400, height: 400, r: 180, arcWidth: 20, data: [ {color: '#ff0000', percent: 0.2, text: '第1项'}, {color: '#ffff00', percent: 0.7, text: '第2项'}, {color: '#ff00ff', percent: 0.1, text: '第3项'} ] }) */ function createArcs (args) { var html = '<svg id="ringSvg" width="' + args.width + '" height="' + args.width + '" >', cx = args.width / 2, cy = args.height / 2, r = args.r, aw = args.arcWidth, data = args.data, i = 0, l = 0, deltaR = 15, //鼠标移动上去时候的偏移值 circleLong = r * 2 * Math.PI, cl2 = (r + deltaR) * 2 * Math.PI, currentReg = 0, itemData = [] html += '<circle class="defaut-arc" cx="' + cx + '" cy="' + cy + '" r="' + r + '" stroke-width="' + aw + '" stroke="none" fill="none"></circle>' l = data.length for (i; i < l; i++) { html += (function (i) { return getCircle(data[i]) }(i)) } function getCircle (d) { var l1 = Math.ceil(circleLong * d.percent), l2 = Math.ceil(circleLong * (1 - d.percent)), l3 = Math.ceil(cl2 * d.percent), l4 = Math.ceil(cl2 * (1 - d.percent)), html = '' // rotate(' + (d.percent * 180 + currentReg * 360) + ', ' + cx + ', ' + cy + ') html = '<circle class="arc-item arc-item' + i + '" cx="' + cx + '" cy="' + cy + '" r="' + r + '" stroke-width="' + aw + '" stroke="' + d.color + '" fill="none" transform="rotate(' + (-90 + currentReg * 360) + ', ' + cx + ', ' + cy + ')" stroke-dasharray="' + l1 + ' ' + l2 + '"></circle>' currentReg = (d.percent * 100 + currentReg * 100) / 100 itemData.push([l1 + ' ' + l2, l3 + ' ' + l4]) return html } html += '</svg>' args.bin.innerHTML = html }
查看 DEMO
为了能够多点交互效果,我们还尝试了设置半径做放大缩小的效果。
//正常时 <circle cx="200" cy="200" stroke-dasharray="189 566" transform="rotate(-90, 200, 200)" r="120" stroke-width="80" stroke="#ff0000" fill="none" ></circle> //放大时 <circle cx="200" cy="200" stroke-dasharray="213 637" transform="rotate(-90, 200, 200)" r="135" stroke-width="80" stroke="#ff0000" fill="none" ></circle>
.arc-item {transition: r ease-in .25s, stroke-dasharray ease-in .25s}
由于半径改变了,所以 stroke-dasharray 也会相应变化,因为周长和半径相关。
这个效果目前在 Chrome 48 下可以完美运行,但 Chrome 42 确认不行,IE 、FF 也不行。可能原因是 CSS 并不支持 r 属性的过渡。因为规范中列出的 CSS 支持的 SVG 属性中并没有 r 属性。
r
以前也没想到过使用百分比设置 stroke-dasharray,这次由于是比例关系,用百分比设置看起来会方便很多,比如 stroke-dasharray="25% 75%",是不是就可以省去周长的计算呢?答案是不行。经过一些测试,发现百分比的参照物并不是圆形自身,而是 svg 元素。百分比的取值也比较奇特,100% 表示的是参照物高宽的平均值,即 (width + height) / 2。
stroke-dasharray="25% 75%"
svg
100%
(width + height) / 2
使用 stroke-dasharray 制作环形图
近期项目中有一个环形图的需求,经过大家研究后决定使用一款开源插件完成。选用插件主要是考虑到需要兼容 IE678,而目前我们团队中没人熟悉 VML。但是这里我仅简单介绍下我们完成的 N 个实验性方案中的一个 —— 使用
stroke-dasharray
制作环形图。原理
以前在《玩转虚线边框》的文章中提及过,SVG 元素可以通过
stroke-dasharray
设置虚线边框的长度以及虚线之间的宽度。所以我们只需要通过圆形的路径,使用虚线长度表述所占百分比即可。比如环状图中有 4 个区域,每个区域各占 25%,那么每个区域应该设置虚线长度为周长的 25%,虚线与虚线之间的间距应该是周长的 75%。
我们可以使用
circle
元素画圆,并指定它的圆心与半径。由于我们最终需要的是圆环,那么我们也需要给圆形指定边宽stroke-width
。加上
stroke-dasharray
之后:stroke-dasharray
的两个值,一个表示虚线的长度,另一个表示虚线与虚线之间的间距,而间距之间是一片空白,所以图形从圆变成了圆弧。然而这好像和我们想象中的有点不一样,我们希望它是从右上方开始的。所以我们需要转换一下坐标系。设置
transform
的rotate
属性,里面的三个参数分别表示旋转的角度、旋转中心的 X 轴坐标,旋转中心的 Y 轴坐标。这里旋转中心就是我们的圆心。这样我们就完成了第一个区域的制作。接下来我们制作第二个区域。第二个区域的圆弧起始位置应该在第一个圆弧的结束位置,即 0 度处(-90 + 360 * 0.25)。
以此类推,我们就可以完成整个环状图的构建工作。
抽象
为了能够更加方便的绘制环状图,我们抽象出了一个方法。
查看 DEMO
过渡动画
为了能够多点交互效果,我们还尝试了设置半径做放大缩小的效果。
由于半径改变了,所以
stroke-dasharray
也会相应变化,因为周长和半径相关。这个效果目前在 Chrome 48 下可以完美运行,但 Chrome 42 确认不行,IE 、FF 也不行。可能原因是 CSS 并不支持
r
属性的过渡。因为规范中列出的 CSS 支持的 SVG 属性中并没有r
属性。用百分比设置 stroke-dasharray
以前也没想到过使用百分比设置
stroke-dasharray
,这次由于是比例关系,用百分比设置看起来会方便很多,比如stroke-dasharray="25% 75%"
,是不是就可以省去周长的计算呢?答案是不行。经过一些测试,发现百分比的参照物并不是圆形自身,而是svg
元素。百分比的取值也比较奇特,100%
表示的是参照物高宽的平均值,即(width + height) / 2
。Thanks