最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • D3基础02 - 对SVG的核心操作

    正文概述 掘金(普通上班族)   2021-01-05   581

    工欲善其事,必先利其器。在了解D3对SVG的核心操作之前,我们首先需要知道什么是SVG,以及SVG绘图的基本用法。

    SVG可缩放矢量图形是一种基于可扩展标记语言,用于描述二维矢量图形的图形格式。SVG由W3C制定,是一个开放标准。

    通过SVG绘制图形

    SVG根视图

    SVG根视图可以认为就是一块画布,所有绘图工作都是在SVG那实现的。SVG初始化时需要配置一些参数:

    • version :SVG的版本
    • xmlns : 命名空间
    • widthheight :SVG画布的吃顿
    • viewBox :视图框,总会在画布中完全显示,其中的图形会基于视图框的宽高按比例显示
    <svg version="1.2" 
         xmlns="http://www.w3.org/2000/svg"
         width="400"
         height="400"
         viewBox="0 0 400 400"
         ></svg>
    

    声明好SVG跟容器之后,我们就可以在svg标签内部进行绘图了,常见的图形如下:

    • 矩形
    • 圆形
    • 路径 ==> 万能绘图方式
      • 直线
      • 圆弧
      • 二次贝塞尔曲线
      • 二次贝塞尔曲线的延续
      • 三次贝塞尔曲线

    下面我们来一个一个的看如何绘制上述图形。

    矩形

    <!--
    rect 矩形
        x|y 矩形左上角点位置
        width|height 尺寸
    -->
    <rect x="100" y="100" width="400" height="400" fill="#00acec" />
    

    圆形

    <!--
        circle 圆形
            cx|cy 圆心位置
            r 半径
        -->
    <circle cx="300" cy="300" r="100" fill="#00acec" />
    

    路径 - 直线

    关于路径(也就是线条),有几个常用的属性,用来控制路径的样式:

    • fill 用来控制路径内部的填充色(闭合曲线才生效)
    • stroks 用来控制路径线条的颜色
    • stroke-width 用来控制线条的宽度
    • stroke-dasharray 用来控制线条的连续性,常用来绘制虚线
    <!--path 路径
        d 路径形状,大写字母为绝对点位,小写字母为相对点位
        起点: M|m
        下一个点: L|l
    -->
    
    <path
      d="
        M
        300 300
        L
        500 300
        "
      fill="none"
      stroke="#000"
      stroke-width="10"
      stroke-dasharray="30 10"
    />
    

    路径 - 圆弧

    <!--圆弧A|a,如 M 300 300 A 150 200 0 0 0 500 300
            rx ry 半径
            x-axis-rotation x轴方向 [0,360]
            large-arc-flag 是否显示最大弧 0|1
            sweep-flag 弧在哪一侧 0|1
            x y 结束点
        -->
    <path
      d="
        M
        300 300
        A
        150 200
        20
        1
        0
        500 300
        "
      fill="none"
      stroke="#000"
      stroke-width="5"
    />
    

    路径 - 二次贝塞尔曲线

    <!--二次贝塞尔曲线 Q|q,如
        M 100 400 
    		Q 200 100 300 400 
        其中200 100 分别是 cpx1 cpy1 控制点,用来控制曲线的弯曲程度
        其中300 400 分别是 x y 结束点
    -->
    
    <path
      d="
        M
        100 400
        Q
        200 100
        300 400
        "
      fill="none"
      stroke="#000"
      stroke-width="10"
    />
    

    二次贝塞尔曲线的延续

    上述我们通过Q|q生成了一段二次贝塞尔曲线,如果我们想要接着画,就需要通过T|t声明接下来曲线的所有控制点。

    <!--二次贝塞尔曲线的延续 T|t,如T 500 400
        x y 结束点
        x y 结束点
        ……
    -->
    
    <path
      d="
        M
        100 400
        Q
        200 100
        300 400
        T
        500 400
        700 400
        900 400
        "
      fill="none"
      stroke="#000"
      stroke-width="10"
    />
    

    三次贝塞尔曲线

    三次贝塞尔曲线与上述二次曲线除了声明的参数变成了C|c以外,唯一的不同之处就在于控制点从一个变成了两个

    <!--三次贝塞尔曲线 C|c,如 M 100 400 C 200 400 200 200 300 200
        上述的 C 200 400 是 cpx1 cpy1 控制点1
        紧接在 C 200 400 后面的 200 200 是cpx2 cpy2 控制点2
        最后的 300 200 是 x y 结束点
    -->
    <path
      d="
        M
        100 400
        C
        200 400
        200 200
        300 200
        "
      fill="none"
      stroke="#000"
      stroke-width="10"
    />
    

    三次贝塞尔曲线的延续

    同上,只需要在继续通过S|s声明所有控制点即可,这时通过S|s声明的控制点只需要声明控制点2即可:

    <!--三次贝塞尔曲线的延续 S|s,如 S 400 400 500 400
    	上述的S 400 400 是 cpx2 cpy2 控制点2
    	500 400 是 x y 结束点
    -->
    <path
      d="
        M
        100 400
        C
        200 400
        200 200
        300 200
        S
        400 400
        500 400
    
        600 200
        700 200
    		"
      fill="none"
      stroke="#000"
      stroke-width="10"
    />
    

    图形容器

    上述的路径属性都用到了一些相同的属性,如fill stroke等,每个path标签内都写这些重复的属性,显然是不够优雅的。并且,如果项目很大,这么多类似的path标签,写着写着我们就不知道哪个path标签对应什么功能了,不便于我们管理。

    所以D3提供了图形容器g,用来统一管理处理同一对象或者同一任务的图形,并管理公共属性。

    <g fill="none" stroke="#000">
      <path
        d="
        M
        100 400
        L
        200 400
        200 200
        300 200
    
        400 400
        500 400
        "
        stroke-width="2"
        stroke-dasharray="3"
      />
      <path
        d="
        M
        100 400
        C
        200 400
        200 200
        300 200
        S
        400 400
        500 400
    
        600 200
        700 200
        "
        stroke-width="10"
      />
    </g>
    

    设置SVG的样式

    其实在上面绘制图形的时候已经通过fill stroke 等属性控制SVG样式了,现在我们以控制SVG图形的颜色为例,来看看详细一下如何设置SVG样式。

    着色按照着色区域可以分为“填充区域”和“描边区域”

    • fill 属性,用来控制填充区域颜色,默认为black,负责填充图形内部的颜色
    • stroke属性,用来控制描边区域,默认为none,负责描边,填充图形轮廓的颜色
    <circle cx="300" cy="300" r="200" fill="rgba(255,100,0,0.5)"/>
    <circle cx="300"
            cy="300"
            r="200"
            fill="none"
            stroke="#00acec"/>
    

    上面都是只填充了纯色,事实上可以使用多种不同着色方式:

    • 纯色
    • 渐变色
      • 线性渐变
      • 径向渐变
    • 纹理

    渐变 - 线性渐变

    通过linearGradient 标签声明线性渐变参数,相关API可详见MDN。

    在标签内通过gradientTransform 属性声明渐变转换的参数:

    1. rotate(a) 控制线性旋转的角度
    2. translate(x,y) 控制x、y方向上的移动
    3. scale(sx,sy) 控制x、y方向上的缩放

    linearGradient 内通过 stop 子标签声明填充的节点颜色。

    1. offset 偏移量[0,1]
    2. stop-color 颜色

    最后在图形标签内,通过 fill="url(#id)" 调用渐变填充颜色

    <defs>
      <linearGradient
        id="gr"
        gradientTransform="rotate(30)"
      >
        <stop offset="0" stop-color="#fff" />
        <stop offset="0.5" stop-color="#00acec" />
        <stop offset="1" stop-color="#fff" />
      </linearGradient>
    </defs>
    
    <circle cx="300" cy="300" r="200" fill="url(#gr)"/>
    

    渐变 - 径向填充

    通过 radialGradient 标签声明径向填充,其余完全一致。

    <defs>
      <linearGradient
        id="gr"
        gradientTransform="rotate(30)"
      >
        <stop offset="0" stop-color="#fff" />
        <stop offset="0.5" stop-color="#00acec" />
        <stop offset="1" stop-color="#fff" />
      </linearGradient>
    </defs>
    <circle cx="300" cy="300" r="200" fill="url(#gr)" />
    

    纹理着色

    可以通过绘制好的SVG图形或者插入的图片,来对图形内部进行纹理填充。

    • pattern 纹理着色

      • id
      • viewBox 视图框
      • width height 纹理元素的尺寸,建议使用百分百
    • polygon 多边形

      • points 点位,如 0,0 20,50 0,100 50,80 100,100 80,50 100,0 50,20
    • image 插入图片

      • href 图片地址
      • x|y 位置
      • widht|height 宽高
    <polygon points="0,0 20,50 0,100 50,80 100,100 80,50 100,0 50,20" />
    <defs>
      <pattern width="30%" height="30%" viewBox="0 0 100 100" id="pt">
        <!--<polygon points="0,0 20,50 0,100 50,80 100,100 80,50 100,0 50,20"/>-->
        <image href="./images/rose.jpg" width="100" height="100" />
      </pattern>
    </defs>
    <circle cx="300" cy="300" r="200" fill="url(#pt)" />
    

    利用D3绘图

    上面已经基本搞通了SVG是如何绘制图形以及如何设置样式的了,那么就通过D3操作DOM元素和SVG,来绘制一个图形吧。

    step1 通过D3的 select 方法获取到main容器。

    const main=d3.select('#main')
    

    step2 在main容器中建立svg跟容器,并设置其相关属性

    const svg=main.append('svg')
            .attr('version',1.2)
            .attr('xmlns','http://www.w3.org/2000/svg')
            .attr('width','100%')
            .attr('height','100%')
            .attr('viewBox','-400 -400 800 800')
    

    step3 在svg容器中建立svg图形,并设置相关属性

    svg.append('rect')
    	.attr('x',-200)
    	.attr('y',-100)
    	.attr('width',400)
    	.attr('height',200)
    	.attr('fill','red')
    

    然后以此类推在svg容器里面添加各种各样的图形,可是我们会发现,这样写要写很多的appen方法,很多很多的attr方法,很不优雅。回过头一看,发现:不管是在main里建立svg容器,还是在svg容器里面添加图形,整体的调用逻辑都是一样的。因此我们可以把这一系列的调用逻辑封装成一个方法。

    step4 封装Render方法,该方法以真实DOM节点作为参数传入,然后返回一个真正的处理函数。该返回函数以需要生成的元素节点和节点属性项为参数传入,并返回真实的元素节点。

    function Render(dom) { // 真实的DOM节点作为参数传入,并直接返回一个处理函数
       return function(shape,option){ // 想要生成的DOM节点、节点配置作为参数传入
           const obj=dom.append(shape)
           for(let [key,val] of Object.entries(option)){ 
             	// 遍历所配置项,并赋值给DOM节点对象
               obj.attr(key,val)
           }
           return obj 
       }
    }
    

    这样,我们就可以直接优雅的通过Render方法添加DOM节点了:

    /*获取main 容器*/
    const main = d3.select("#main");
    function Render(dom) {
      return function (shape, option) {
        const obj = dom.append(shape);
        for (let [key, val] of Object.entries(option)) {
          obj.attr(key, val);
        }
        return obj;
      };
    }
    
    const svg = Render(main)("svg", {
      version: 1.2,
      xmlns: "http://www.w3.org/2000/svg",
      width: "100%",
      height: "100%",
      viewBox: "-400 -400 800 800",
    });
    // 获取到创建DOM节点的方法
    const draw = Render(svg);
    /*绘制图形……*/
    draw("rect", {
      x: -200,
      y: 0,
      width: 400,
      height: 200,
      fill: "red",
    });
    draw("rect", {
      x: -200,
      y: 0,
      width: 400,
      height: 200,
      fill: "none",
      stroke: "#000",
      "stroke-width": 40,
    });
    draw("rect", {
      x: -200,
      y: 50,
      width: 400,
      height: 60,
      fill: "antiquewhite",
    });
    draw("path", {
      d: `
                M
                -100 150
                L
                100 150
            `,
      fill: "none",
      stroke: "#000",
      "stroke-width": 40,
    });
    draw("circle", {
      cx: -100,
      cy: 80,
      r: 20,
      fill: "red",
    });
    draw("path", {
      d: `
                M
                80 90
                A
                20 20
                0
                0
                1
                120 90
            `,
      fill: "red",
    });
    draw("path", {
      d: `
                M
                -200 -200
                C
                -100 -200
                -100 0
                0 0
                S
                100 -200
                200 -200
            `,
      fill: "none",
      stroke: "#000",
      "stroke-width": 40,
    });
    

    以上,便是通过D3操作DOM实现SVG绘图的实例。


    起源地下载网 » D3基础02 - 对SVG的核心操作

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元