教你一招在SVG路径中间增加图标~

448 阅读2分钟

需求背景

在某个项目中,需要自行画一条svg直线,然后svg还需要在起始点、终点和中点额外添加图标,这就研究了一下 marker 和 CSS运动路径

marker-start/-mid/-end

我们先看在主要的一些场景下,它们的可行性

直线

代码如下,预期结果,三点均有图标

// css
.line {
    fill: none;
    stroke: red;
    stroke-width: 2px;
    marker-start: url(#markerCircle);
    marker-end: url(#markerCircle);
    marker-mid: url(#markerCircle);
}

// marker svg定义
<svg width="0"
    height="0"
    style="position: absolute;">
    <defs>
        <marker id="markerCircle"
            markerWidth="8"
            markerHeight="8"
            refX="4"
            refY="4">
            <circle cx="4"
                cy="4"
                r="2.5">
        </marker>
    </defs>
</svg>

// 直线 svg
<svg>
    <line class="line" x1="10"
        y1="10"
        x2="130"
        y2="10"></line>
</svg>

实际效果,起始、终点都ok,中间没有

image.png

结论:marker-mid在直线中不起作用

折线

// css 和 marker svg定义一样

// 折线 svg
<svg>
    <polyline class="line" points="20,100 50,60 80,80 110,20 140,60 170,40 200,90">
</svg>

实际效果,起始、终点都ok,中间每个转折点都有

image.png

结论:marker-mid在折现的每个转折点生效

弧线

// 弧线 svg
<svg>
    <path class="line"
        d="M30 90 Q115 139 200 90"></path>
</svg>

实际效果,起始、终点都ok,中间没有

image.png

结论:marker-mid在弧线中不起作用

贝塞尔

// 贝塞尔 svg
<svg>
    <path class="line"
        d="M30 100 Q 80 30,100 100 T 200 80" />
</svg>

实际效果,起始、终点都ok,中间也有,但位置不是我想要的

image.png

再看另一个贝塞尔

<svg>
    <path class="line"
        d="M30 100 Q 80 30,100 100,130 65,200 80" />
</svg>

实际效果同上

image.png

结论:marker-mid在贝塞尔线中起部分作用

CSS运动路径

既然marker-mid不行,就又尝试了一下CSS运动路径

CSS运动路径是什么?

CSS运动路径全名是 CSS Motion Path;
用这个属性,我们可以控制元素按照特定的路径进行位置变换的动画, 并且,这个路径可以是非常复杂的一条路径。 由于是css动画,所以动画的性能也比较高,动画流畅,画面不卡, 在实现控制物体按照制定路径运动效果的时候,这个是首选。

主要属性有哪些

  • offset-path:接收一个 SVG 路径(就是SVG中的Path),以此来确定运动路径
  • offset-distance:控制当前元素基于 offset-path 运动的距离, 0%就是开始位置, 100%就是走到路径的终点
  • offset-position:指定 offset-path 的初始位置
  • offset-rotate:定义沿 offset-path 定位时元素的方向,说人话就是运动过程中元素的角度朝向

居中图标

// css
.circle {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background-color: black;
    position: absolute;
    offset-distance: 50%; /* 中间位置 */
    offset-path: path("M10,10 L100,10");

}


// 小图标
<div class="circle"></div>

// 直线svg
<svg>
    <path d="M10,10 L100,10" class="line" />
</svg>

实际效果

image.png