自定义图像沿svg路径运动

笑的咪咪青藤

平时经常会用到svg,都是用工具生成,直接拿来用。当项目要用到自定义图像做路径运动的时候就需要自己动手手辣。
这几天做项目常用到这几个效果,写一个文章归纳。
6e24ada9-2718-4d4a-bc0d-bcc8e6064f62.png

我们康康示例效果


二次贝塞尔曲线

svg2.gif

三次次贝塞尔曲线

svg.gif
微信截图_20191212103818.png

回顾svg贝塞尔曲线指令


二次贝塞尔曲线

Q x1 y1 x y ;(x1,y1)是控制点,(x,y)代表曲线的终点。

三次贝塞尔曲线指令

Cx1 y1, x2 y2; (x1,y1)和(x2,y2)分别是两个控制点,(x,y)代表曲线的终点。
网上资料很多哒,不足自己去找找哈

入正题写代码


自定义一个图像 也就是例子中运动的小球
<defs>
    <pattern id="imgpattern" x="0" y="0" width="40" height="40">
        <image width="40" 
            height="40"
            xlinkHref="data:image/svg+xml;base64,此处是一个svg格式的base64图片哦" />
    </pattern>
</defs>

<defs>标签内定义图案;
<pattern>是一个填充标签;元素中的内容直到引用的时候才会显示,<pattern>标签里面必须定义一个id,这个id是你后面要引用的地方需要使用的你也可以定义宽度高度;
<image>是我例子中运动的小球,好像必须要转成base64才可以,我直接用的图片路径不行啊...让我在康康...如果不需要图片,你也可以使用<text>或者 <circle> 等等,看起来很简单但是。。。![
微信截图_20191212105649.png](/img/bVbBop4)查了好久的资料。。最后在一个英文文档中看见,但是看了以后链接就没有存上。

定义padth

自定义的图我们也定义好啦,那就写path啦
我们看三次贝塞尔曲线中的例子,有12根线,那就需要一个起点,终点还有两个控制点啦
微信截图_20191212110147.png
因为例子中的球有12根线,我们用代码生成吧

// getElementPosition是自定义获取dom的位置的方法
svgChart = () => {
    let beginPoint = getElementPosition(this.beginPoint); // 起点
    let endPoint = getElementPosition(this.endPoint); // 终点dom 
    let lines = [];
    for (let i = 0; i < 12; i++) {
        lines.push({
            name: `path${i}`,
            path: [
                [endPoint.x, endPoint.y],
                [-65 + (50 * i), 180], // 控制点1
                [-65 + (50 * i), 28], // 控制点2
                [beginPoint.x, beginPoint.y]
            ],
            lineStyle: {
                fill: 'transparent',
                stroke: '#006ecf',
                strokeWidth: 1
            }
        });
        this.setState({ lines });
    }
}
<div className={styles.arthTurn} ref={c => this.svgContent = c}>
        <svg
            width="100%"
            height="100%"
            version="1.1">
            <defs>
                <pattern id="imgpattern" x="0" y="0" width="40" height="40">
                    <image width="40" height="40"
                        xlinkHref="此处是一个svg格式的base64图片哦" />
                </pattern>
            </defs>
            {
                lines.map((d, index) => {
                    let path = [];
                    d.path.forEach((p, i) => {
                        switch (i) {
                            case 0:
                                p = `M${p[0]},${p[1]}`;
                                break;
                            case 1:
                                p = `C${p[0]},${p[1]}`;
                                break;
                            case 2:
                                p = `${p[0]},${p[1]}`;
                                break;
                            case 3:
                                p = `${p[0]},${p[1]}`;
                                break;
                        }
                        path.push(p);
                    });
                    path = path.join(' ');
                    const { fill = 'transparent', stroke = '#000', strokeWidth = 2 } = d.lineStyle || {};
                    return (
                        <Fragment>
                            <path
                                key={d.id}
                                fill={fill}
                                stroke={stroke}
                                strokeDasharray="3,3"
                                d={path}
                                strokeWidth={strokeWidth}
                                className="path"
                            />
                        </Fragment>
                    );
                })
            }
        </svg>
        {/* 起点 */}
        <div className={styles.beginPoint} ref={c => this.beginPoint = c}></div>
        {/* 终点 */}
        <div className={styles.endPoint} ref={c => this.endPoint = c}></div>
    </div>

我们将看见一下图中一样的12跟虚线
微信截图_20191212110753.png
欧克欧克。。快了快了

将定义的图用上,让图形动起来
<Fragment>
        <path
            key={d.id}
            fill={fill}
            stroke={stroke}
            strokeDasharray="3,3"
            d={path}
            strokeWidth={strokeWidth}
            className="path"
        />
        <rect x="-20" y="-20" width="40" height="40" fill="url(#imgpattern)">
            <animateMotion path={path} begin={animatTime} dur="6s" repeatCount="indefinite" />
        </rect >
    </Fragment>

代码中我们定义了一个宽度和高度分别为40的矩形,填充背景是我们上面定义的图。这里fill="url(#imgpattern)对应的也是以上自定义的图形id。
欧克欧克。。再配合<animateMotion>不过此标签好像不支持ie哦;还有一种方式是css:offset-path: path("M 208 231 C -65 180 -65 28 208 0");好像最兼容的是用translate3d但是麻烦一点,下次可以更新这个兼容ie的方法哦
ac64418a-5045-4069-bf69-32bd818c4d12.png

差不多就这样啦。另外一个例子中就不说啦。那个和这个一样,只是少了一个控制点而已哦

阅读 1.3k
1 声望
0 粉丝
0 条评论
1 声望
0 粉丝
宣传栏