Developer Wiki

In-depth guide for developers to create stencils and templates

Drawing Path - The D Behavior

Pencil shape is usually created by paths that base on SVG path specification. Pencil simply supports drawing shapes by the D behavior. This behavior generates the "d" attribute for the <path> SVG element as defined in the SVG Path data specification . The value used in D is an array in which each item is a drawing command.

The shape in this tutorial is a triangle drawn from 3 points that are defined by properties of type Handle .

<Shape id="triangle" displayName="Triangle" icon="Icons/triangle.png">
  <Properties>
    <PropertyGroup>
      <Property name="a" displayName="Point" type="Handle">0,0</Property>
      <Property name="b" displayName="Point" type="Handle">90,0</Property>
      <Property name="c" displayName="Point" type="Handle">45,60</Property>
    </PropertyGroup>
    <PropertyGroup name="Border">
      <Property name="strokeColor" displayName="Line Color"
                type="Color">#1B3280ff</Property>
      <Property name="strokeStyle" displayName="Line Style"
                type="StrokeStyle">2|</Property>
    </PropertyGroup>
  </Properties>
  <Behaviors>
    <For ref="path">
      <StrokeColor>$strokeColor</StrokeColor>
      <StrokeStyle>$strokeStyle</StrokeStyle>
      <D>[M($a.x, $a.y), L($b.x, $b.y), L($c.x, $c.y), z]</D>
    </For>
  </Behaviors>
  <p:Content xmlns:p="http://www.evolus.vn/Namespace/Pencil"
             xmlns="http://www.w3.org/2000/svg">
    <path id="path" fill="none" style="stroke-linejoin: round;" />
  </p:Content>
</Shape>

In the above example, Handle properties provide points that can be moved on the drawing canvas. Their values are changed upon the move and the behavior code will be executed to re-generate the path's "D" value.

You can notice that various commands are used in this example. Pencil supports to following SVG Path commands: M, L, l, C, c, S, s, Q, q, T, A and a.

In many other situations, paths may not rely soly on position of handles. For example, a triangle can also be drawn basing on a bounding box in the following example:

<Shape id="triangle" displayName="Triangle" icon="Icons/triangle .png">
  <Properties>
    <PropertyGroup>
      <Property name="box" type="Dimension">200,80</Property>
      <Property name="strokeColor" displayName="Line Color"
                type="Color">#1B3280ff</Property>
      <Property name="strokeStyle" displayName="Line Style"
                type="StrokeStyle">2|</Property>
    </PropertyGroup>
  </Properties>
  <Behaviors>
    <For ref="path">
      <StrokeColor>$strokeColor</StrokeColor>
      <StrokeStyle>$strokeStyle</StrokeStyle>
      <D>[M(0, 0), L($box.w, 0), L($box.w/2, $box.h), z]</D>
    </For>
  </Behaviors>
  <p:Content xmlns:p="http://www.evolus.vn/Namespace/Pencil"
             xmlns="http://www.w3.org/2000/svg">
    <path id="path" fill="none" style="stroke-linejoin: round;" />
  </p:Content>
</Shape>

It is very convenient to create shape with specific points based on handles and box. The "D" behaviour is used heavily in the built-in Flowchart stencil collection .

Add Transparent Background

The 2 examples above generate no-filled triangles so it is very difficult for users to drag and move the objects on the drawing canvas. To avoid this, the suggested way is to create a transparent path as the background below the triangle with thicker stroke.


<Shape ...>
    ....
  <Behaviors>
    <For ref="bgpath">
      <D>[M($a.x, $a.y), L($b.x, $b.y), L($c.x, $c.y), z]</D>
    </For>
    <For ref="path">
        ...
    </For>
  </Behaviors>
  <p:Content ...>
    <path id="bgpath" fill="none"
          style="stroke: rgba(0, 0, 0, 0); stroke-width: 10px;"/>
    <path id="path" fill="none" style="stroke-linejoin: round;" />
  </p:Content>
</Shape>