SVG—04-绘制路径path

1,316 阅读4分钟

概要总结

    1、path路径概念

    2、path绘制三角形

    3、path绘制二次贝塞尔曲线

    4、二次贝塞尔曲线算法

一、path路径概念

    1、d: 绘制路径的命令,d是draw的缩写,是绘制的意思。以下是d的常用命令:

        (1)M:M命令是moveto的缩写,定义绘制图形的起点坐标。例如M 150 0,也可以写成M150 0,表示路径从屏幕坐标的x150,y0这个点开始绘制

image.png

        (2)L:L命令是lineto的缩写,用来绘制一条直线,例如l 75 200,也可以写成l75 200,表示从上一个结束点到x75,y200这个点绘制一条直线。

image.png

    2、命令字母大小写

        命令的字母大小写表示的意义是不同的,大写字母表示绝对定位,小写字母表示相对定位。

image.png

        绝对定位是相对于屏幕坐标原点的位置,相对定位是相对于上一个绘制点的位置。

image.png

二、path绘制三角形

<svg width="400" height="210" style="background: #eee">
  <path d="M150 0 L75 200 L225 200"/>
</svg>

    它的绘制流程,首先它把画笔移动到150,0的顶点位置,从这个位置画到75,200的左下角,然后再画到225,200右下角的位置,最后连接回起始的顶点位置。

image.png

三、path绘制二次贝塞尔曲线

    1、概念

        在path中绘制"二次贝塞尔曲线"使用Q命令,q是quardratic Bézier curve的缩写,用来绘制二次贝塞尔曲线。

    2、绘制原理

        需要定义控制点和终点的坐标,例如q 150 -300 300 0,表示控制点坐标是x 150, y -300,终点坐标是x 300, y0。

        二次贝塞尔曲线的绘制示意图:

image.png

        A为起点,B为控制点,C为终点,在AB、BC两条红色的线段上有一条绿色的切线,蓝色的为绘制的二次贝塞尔曲线。

image.png

    3、绘制过程

        (1)绘制起点、控制点和终点

<svg width="550" height="400" style="background: #eee">
  <circle cx="100" cy="350" r="3"/>
  <circle cx="250" cy="50" r="3"/>
  <circle cx="400" cy="350" r="3"/>
</svg>

            在SVG中,我们可以使用g标签把多个绘图元素包裹起来,在g标签上定义公共的属性。

<svg width="550" height="400" style="background: #eee">
  <g fill="black">
    <circle cx="100" cy="350" r="3"/>
    <circle cx="250" cy="50" r="3"/>
    <circle cx="400" cy="350" r="3"/>
  </g>
</svg>

image.png

        (2)绘制A、B、C三个点的文本

<svg width="550" height="400" style="background: #eee">
  <g fill="black">
    <circle cx="100" cy="350" r="3"/>
    <circle cx="250" cy="50" r="3"/>
    <circle cx="400" cy="350" r="3"/>
  </g>
  <g font-size="20" fill="black">
    <text x="90" y="380">A(100, 350)</text>
    <text x="250" y="40">B(250, 50)</text>
    <text x="400" y="380">C(400, 350)</text>
  </g>
</svg>

image.png

        (3)绘制AB、BC两条连线

            <path d="M 100 350 l 150 -300" stroke="red" stroke-width="3" fill="none"/>             <path d="M 250 50 l 150 300" stroke="red" stroke-width="3" fill="none"/>

<svg width="550" height="400" style="background: #eee">
  <path d="M 100 350 l 150 -300" stroke="red" stroke-width="3" fill="none"/>
  <path d="M 250 50 l 150 300" stroke="red" stroke-width="3" fill="none"/>
  
  <g fill="black">
    <circle cx="100" cy="350" r="3"/>
    <circle cx="250" cy="50" r="3"/>
    <circle cx="400" cy="350" r="3"/>
  </g>
  <g font-size="20" fill="black">
    <text x="90" y="380">A(100, 350)</text>
    <text x="250" y="40">B(250, 50)</text>
    <text x="400" y="380">C(400, 350)</text>
  </g>
</svg>

image.png

        (4)绘制绿色切线

<svg width="550" height="400" style="background: #eee">
  <path d="M 100 350 l 150 -300" stroke="red" stroke-width="3" fill="none"/>
  <path d="M 250 50 l 150 300" stroke="red" stroke-width="3" fill="none"/>
  <path d="M 175 200 l 150 0" stroke="green" stroke-width="3" fill="none"/>
  
  <g fill="black">
    <circle cx="100" cy="350" r="3"/>
    <circle cx="250" cy="50" r="3"/>
    <circle cx="400" cy="350" r="3"/>
    <circle cx="175" cy="200" r="3"/>
    <circle cx="325" cy="200" r="3"/>
  </g>
  <g font-size="20" fill="black">
    <text x="90" y="380">A(100, 350)</text>
    <text x="250" y="40">B(250, 50)</text>
    <text x="400" y="380">C(400, 350)</text>
    <text x="50" y="200">D(175, 200)</text>
    <text x="340" y="200">E(325, 200)</text>
  </g>
</svg>

image.png

        (5)绘制贝塞尔曲线

<svg width="550" height="400" style="background: #eee">
  <path d="M 100 350 l 150 -300" stroke="red" stroke-width="3" fill="none"/>
  <path d="M 250 50 l 150 300" stroke="red" stroke-width="3" fill="none"/>
  <path d="M 175 200 l 150 0" stroke="green" stroke-width="3" fill="none"/>
  <path d="M 100 350 q 150 -300 300 0" stroke="blue" stroke-width="5" fill="none"/>
  
  <g fill="black">
    <circle cx="100" cy="350" r="3"/>
    <circle cx="250" cy="50" r="3"/>
    <circle cx="400" cy="350" r="3"/>
    <circle cx="175" cy="200" r="3"/>
    <circle cx="325" cy="200" r="3"/>
    <circle cx="250" cy="200" r="3"/>
  </g>
  <g font-size="20" fill="black">
    <text x="90" y="380">A(100, 350)</text>
    <text x="250" y="40">B(250, 50)</text>
    <text x="400" y="380">C(400, 350)</text>
    <text x="50" y="200">D(175, 200)</text>
    <text x="340" y="200">E(325, 200)</text>
    <text x="195" y="230">F(250, 200)</text>
  </g>
</svg>

image.png

        (6)清除所有点和辅助线

<svg width="450" height="400" style="background: #eee">
  <path d="M 100 350 q 150 -300 300 0" stroke="blue" stroke-width="5" fill="none"/>
</svg>

image.png

        (7)非常规三角形的贝塞尔曲线

<svg width="550" height="500" style="background: #eee">
  <path d="M 100 250 l 200 -200" stroke="red" stroke-width="3" fill="none" />
  <path d="M 300 50 l 100 350" stroke="red" stroke-width="3" fill="none" />
  <path d="M 200 150 l 150 75" stroke="green" stroke-width="3" fill="none" />
  <path d="M 100 250 q 200 -200 300 150" stroke="blue" stroke-width="5" fill="none"/>
  
  <g fill="black">
    <circle cx="100" cy="250" r="3"/>
    <circle cx="300" cy="50" r="3"/>
    <circle cx="400" cy="400" r="3"/>
    <circle cx="200" cy="150" r="3"/>
    <circle cx="350" cy="225" r="3"/>
    <circle cx="275" cy="187.5" r="3"/>
  </g>
  <g font-size="20" fill="black">
    <text x="90" y="275">A(100, 250)</text>
    <text x="300" y="40">B(300, 50)</text>
    <text x="400" y="425">C(400, 400)</text>
    <text x="80" y="150">D(200, 150)</text>
    <text x="360" y="230">E(350, 225)</text>
    <text x="270" y="180">F(275, 187.5)</text>
  </g>
</svg>

image.png

    4、代码演示

四、二次贝塞尔曲线算法

    贝塞尔曲线起点和终点对应的就是三角形的两个底角,而曲线的控制点就是顶角,目前未知。但曲线的最高点是已知的,它实际上就是三角形的中线的中点。

image.png

    由图可知,曲线的起点是A,终点是C,最高点是F。而最高点F实际上是AB和CB的中点连线的中点。

    一条贝塞尔曲线需要3个条件,分别是起点、终点和控制点,这个控制点可以理解为三角形的顶角B。已知A和C两个角的坐标,因此可以求出AC的中点G坐标为(250, 325)。最高点F是曲线的最高点也是已知的,根据三角形定理,BG是三角形BAC的中线,F是BG的中点,假设B点的x坐标为x,y坐标为y,可以根据以下公式:

    (x + 250) / 2 = 275

    (y + 325) / 2 = 187.5

    因此B点的坐标为(300, 50)。现在起点、终点和控制点都已具备,那么可以通过path的q将这条贝塞尔曲线绘制出来。

五、代码链接

gitee.com/huang_jing_…