需求是提取 svg 上的所有的 path(fill 属性不能为 none),并将它们显示到列表里,要求 path 刚好在 svg 的中间位置。
为了简化代码,使用了 SVG.js 库。本文主要是记录解决思路和一些要注意的地方,理解了你可以改成原生的写法。
在线demo(需要科 学上 网)
codepen上的在线demo(可以访问!)
思路
首先我们要遍历一下,找出所有符合条件的 path。这个很简单,有点麻烦的是让 path 居中,并让 svg 自适应。
首先我们需要一个 svg 来包裹 path。为了让 svg 可以自适应它的父容器,我们需要给它 viewbox 属性。
viewbox 的计算
那么 viewbox 要怎么计算呢?我们可以通过 path 元素的 bbox 来获取该元素占据的位置和宽高,作为 viewbox 的宽高基准。另外不要忘记的是,bbox 的计算是不包括 stroke 的,所以你还要记录一下 path 的线宽,此外你还可以自行设置 path 到 svg 的内边距 padding,让 path 不会刚好碰到容器边缘,而是保持一定的距离。
svg 的 viewBox 的宽: path 的宽
+ 线宽
+ padding * 2
。
同理,svg 的 viewBox 的高: path 的高
+ 线宽
+ padding * 2
这里线宽没有乘2,是因为 svg 里,path 的轮廓线是 stroke 的中线,也就是从没有 stroke 到 加上 stroke,整个 path 只是向外走了二分之一的 stroke-width。所以我们乘上2也就变成了 stroke-width。
至此,viewbox 计算完毕。
path 的计算
下面我们处理 path。
首先要知道 path 的左上角的位置。
emmm....没错,你说的没错就是:[padding + strokeWidth / 2, padding + strokeWidth/ 2]
画图看看你就明白了(自己画吧)。
然后我们要做的是移动位置,因为 path 在原来的 svg 上不一定刚好处于左上角位置。所以你要移动 path 到前面算出的左上角。
通过 bbox 获得原来 path 的左上角的坐标,计算出和目标坐标的差值dx 和 dy。修改位置的方法有两种:
- 对 d 属性上的点都进行计算(没有使用 svg 库的话要自己写算法)
- 使用 transform 属性 的 translate 方法。
至此我们的 path 也计算好了。
核心代码
/**
*
* @param {SVGjs.Element} el svgjs库的元素对象
*/
function showPaths(el) {
const padding = 20,
strokeWidth = el.attr('stroke-width') == undefined ? 0 : el.attr('stroke-width'),
svgW = el.bbox().width + strokeWidth + padding * 2,
svgH = el.bbox().height + strokeWidth + padding * 2;
let svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
let s = SVG(svg)
.viewbox(0, 0, svgW, svgH);
el = el.clone()
.addTo(s)
.move(padding + strokeWidth / 2, padding + strokeWidth/ 2)
// s.rect(el.bbox().width, el.bbox().height).stroke('#000').fill('none')
let li = document.createElement('li');
li.append(svg);
ul.append(li);
}
可添加的功能
我们还可以给 li 绑定事件,每当点击 li 时,高亮对应的 path。