Make sure you have the Basic stencils activated. Click More Shapes and the dialog, make sure the Basic group is active. Close the dialog and drop the 4 Point Star stencil on the canvas. You should select the Edit Shape button in the Format Panel, while only the 4 Point Star stencil is selected.
The basic draw.io stencils use XML. In the Edit Shape dialog you can see the XML structure of the stencil. Delete all the text.
The top level element is "shape". So enter:
<shape name="stencilName" h="100" w="50" aspect="variable" strokewidth="inherit"> </shape>
Its attributes are:
- name - stencil name
- h - height
- w - width
- aspect - if variable, you can have any aspect ratio. if fixed, h and w are fixed to the ratio you defined in h and w.
- strokewidth - inherit sets strokewidth to the style you define in the UI. Set it to a positive number and it will be fixed to that width.
The shape block can contain 3 child elements defined in the following order:
- <connections> - connection points for edges
- <background> - geometry defined here will have shadows
- <foreground> - the rest of the geometry
We will deal with connections later.
Let's create the geometry for the background:
<background> <path> <move x="0" y="0"/> <line x="50" y="0"/> <line x="50" y="40"/> <line x="100" y="40"/> <line x="100" y="50"/> <line x="0" y="50"/> <close/> </path> </background>
The coordinate 0, 0 is always the top left point. The bottom right is w, h, so in this case it's 100, 50.
Now add some foreground geometry:
<foreground> <path> <move x="25" y="10"/> <line x="25" y="40"/> </path> </foreground>
Every geometry element has to have a defined stroke. It can be stroke, fill or fillstroke. Stroke is stroke without fill, fill is fill without stroke, and fillstroke is both fill and stroke. First, the geometry should be defined and preferably the next line should be the stroke type.
After all this, our shape should be looking something like this:
<shape name="stencilName" h="50" w="100" aspect="variable" strokewidth="inherit"> <background> <path> <move x="0" y="0"/> <line x="50" y="0"/> <line x="50" y="40"/> <line x="100" y="40"/> <line x="100" y="50"/> <line x="0" y="50"/> <close/> </path> </background> <foreground> <fillstroke/> <path> <move x="25" y="10"/> <line x="25" y="40"/> </path> <stroke/> </foreground> </shape>
Notice the stroke exception in the case of background geometry. You don't define it after the background geometry, but instead as the first line of the foreground block.
Click Preview and you should see:
There are 4 types of geometry elements:
- <rect> attributes "x", "y", "w", "h", all required decimals
- <roundrect> attributes "x", "y", "w", "h", all required decimals. Also "arcsize" an optional decimal attribute defining how large, the corner curves are.
- <ellipse> attributes "x", "y", "w", "h", all required decimals.
- <path> a general case of geometry
Path is a similar structure as path in SVG. It should start with a <move> where "x" and "y" define the coordinate. After move, an arbitrary number of geometry elements should follow.
Path elements can be:
- <move> to attributes required decimals (x,y).
- <line> to attributes required decimals (x,y).
- <quad> to required decimals (x2,y2) via control point required decimals (x1,y1).
- <curve> to required decimals (x3,y3), via control points required decimals (x1,y1) and (x2,y2).
- <arc>, this doesn't follow the HTML Canvas signatures, instead it's a copy of the SVG arc command. The SVG specification gives the best description of its behaviors. The attributes are named identically, they are decimals and all required.
- <close> ends the current subpath and causes an automatic straight line to be drawn from the current point to the last move point of the current subpath.
When the subpath is finished, there are two options. to finish it with </path>, which makes is visually open. The second option is to use <close> and then </path>, which will close the current subpath. A subpath is a segment which starts with a <move> and ends with a <close> or another <move>. A single <path> can contain multiple subpaths, but all of them will use the same style. And if they overlap, the same fill rule applies as for SVG.
The first element of geometry will use the shadow style if needed, but the rest will not.
The <connections> element defines the connection points of the stencil, where edges can be connected.
<connections> <constraint x="0.5" y="0"/> <constraint x="0.5" y="1"/> <constraint x="0" y="0.5"/> <constraint x="1" y="0.8"/> </connections>
This adds 4 connection points at the corresponding coordinates. Note the coordinates are relative. x=0 is 0, x=1 is full width. Same for y.
Style functions similar to the SVG style specification. Until you defined a specific style, the style applied to the stencil will be in effect.
Style types are:
alpha - defines alpha level, the opposite of transparency. Attribute is alpha and range is 0-1, decimal. 0 being fully transparent and 1 being solid.
- strokewidth - defines stroke width in pixels. Attributes are width which is decimal and fixed is optional, default 0 being scaling with resize and 1 for fixed stroke width regardless of scaling.
- dashed - toggles dashed line style. Attribute is dashed. ) for full line, 1 for dashed.
- dashpattern - defines dashed line style. Attribute is pattern and is an array. The numbers in the array define for how many points there is a line, the next one the pause, then line again, and so on. Imagine the numbers as on/off alternating until the end of the array and then starting over. So <dashpattern pattern="5 1 8 1"/> defines a line length 5, pause of 1, even longer line of 8, another pause of 1 and starting over.
- miterlimit - same as in SVG. Attribute is limit, a decimal number. It defines the "edginess" of line joins. The larger the number, the bigger spikes are allowed on sharp joins. The limit attribute defines the cutoff amount for spikes.
- linejoin - defines the type of line joining. Attribute is join and can be miter, round or bevel, same as in SVG. Default is miter, and it produces straight sharp edges. Round as the name says gives rounded joins. Bevel is the middle solution, as it produces "rounded" joins, but instead a curve, a straight line.
- linecap - defines the type of line end. Attribute is cap and can be flat, square or round, same as in SVG. Default is flat, and it produces a square edge right at the end of the line. Round as the name says gives rounded ending, after the line end, so the line is a bit longer. Square is the middle solution, as it produces "rounded" ends, but instead a circular curve, a squared straight line at the end.
There are some more style that are related to text.
Text is added using the text element. It uses the following format:
<text str="someText" x="50.0" y="50.0" align="left" valign="top" vertical="0" rotation="0.0" align-shape="1"/>
Required attributes are str, x and y. Align, valign, localized, vertical, rotation and align-shape are all optional. Str defines the actual text the element will use and is a string. X and y are label coordinates and use a decimal value. Align defines horizontal alignment and its self-descriptive values are: left, center and right. Similar for the valign attribute that is used to define vertical alignment. Its possible values are top, middle and bottom. If vertical is 1 the text is rendered vertically, if 0 (default) it uses horizontal text. Rotation defines text rotation and is in the range of 0.0 to 360.0. Finally align-shape defines if the text label should rotate with the shape (value of 1), or should always stay fixed (value of 0).
The styles related to text are:
- fontsize - attribute is size and is a decimal value. Defines font size.
- fontstyle - attribute is style and is an ORed bit pattern of bold (1), italic (2) and underline (4), i.e bold underline is "5"
- fontfamily - attribute is family and is a string defining the typeface to be used
Unless you defined a style inside the stencil, it will use the default style applied to it. In the case of the above example, you can change fill color and stroke color and it will affect the whole stencil. Let's say we want to keep the behavior of the outline stroke (it changes as we change strokecolor from the UI), but we want that vertical line to be white. Lets call the outline geometry <path1> and the vertical line <path2>. We should do conceptually something like this:
<path1> <fillstroke/> <strokecolor color="#ffffff"/> <path2/> <stroke/>
Now assume we have another line we will call <path3> which is declared after <path2> and we want it to have the default stroke color. Since we already defined it to be white, we need a mechanism to solve this. For this reason the format has a stack mechanism. By entering a <save/> element, we save the current style on the stack. If we use a <restore/> later, we reset the current style to the last save that is in the stack. The stack uses the standard LIFO (last in, first out) structure.
<save/> //saving all the styles here, which are unchanged, so the default ones <path1> <fillstroke/> //use default fill and stroke <strokecolor color="#ffffff"/> <path2> <stroke/> //use white stroke, if it was fillstroke, white stroke and default fill color would be used <restore/> // we restore the last saved state, which in this case contains the default styles <path3> <stroke/> //uses the same stroke color as the first time (the white fill got overwritten in the meantime)
The number of <save/> and <restore/> elements should match.