technodesigner

Digital design

Olivier Dewit
Template based code generation - Part 2 : richer SVG scene, indentation

Template based code generation - Part 2 : richer SVG scene, indentation

Series index

Next parts of this article assume that the tdCodeFactory module is installed and opérational.

In the Github repository , the source code for this example is available in the Demo/2.ShapeFactory and Demo/CsCode folders.

SVG scene with several objects

Our second example is to produce an SVG file that defines several rectangles with rounded corners. Fill and stroke are defined by a CSS style.

The template (rect.svg.template file) expects from the script block the following variables:

The template uses the data from C# classes (which are introduced in the part 1):

<svg xmlns="http://www.w3.org/2000/svg"
  viewBox="0 0 $($shapeboard.Width) $($shapeboard.Height)">
  <defs>
    <style type="text/css">
      <![CDATA[
    $(foreach ($style in $styles){"
        $($style.Target).$($style.Name){
          fill: $($style.Fill);
          stroke: $($style.Stroke);
          stroke-width: $($style.StrokeThickness);
        }`r`n"})
      ]]>
    </style>
  </defs>
  <rect 
    x='0' 
    y='0' 
    width='$($shapeboard.Width)' 
    height='$($shapeboard.Height)'
    fill='#FFCC4D' />
  $(foreach ($rect in $shapes){"
  <rect 
    class='$($rect.StyleDataName)' 
    x='$($rect.X)'
    y='$($rect.Y)'
    width='$($rect.Width)'
    height='$($rect.Height)'
    rx='$($rect.RadiusX)'
    ry='$($rect.RadiusY)'/>`r`n"})
</svg>

Script

The ShapeFactory.ps1 script file initializes in the script block the styles data (ShapeStyleData objects), rectangles (RectData objects) and arrays, and then calls the Export-FileFromTemplate command to generate the SVG file:

$code = {
  $shapeStyleDataCsCode = Import-CodeTemplate $PSScriptRoot\..\CsCode\ShapeStyleData.cs
  Add-Type -Language CSharp $shapeStyleDataCsCode
  $rectStyle1 = New-Object CodeFactory.ShapeStyleData -Property @{
    Name = "rectStyle1";
    Target = "rect";
    Fill = "#FFA500";
    Stroke = "#28282A";
    StrokeThickness = 2;
  };
  $rectStyle2 = New-Object CodeFactory.ShapeStyleData -Property @{
    Name = "rectStyle2";
    Target = "rect";
    Fill = "#F5331F";
    Stroke = "#28282A";
    StrokeThickness = 2;
  };
  $script:styles = @(
    $rectStyle1;
    $rectStyle2 )
  $rectDataCsCode = Import-CodeTemplate $PSScriptRoot\..\CsCode\RectData.cs
  Add-Type -Language CSharp $rectDataCsCode
  $rect1 = New-Object CodeFactory.RectData -Property @{
    Name = "rect1";
    StyleDataName = $rectStyle1.Name;
    X = 10;
    Y = 10;
    Width = 80;
    Height = 40;
    RadiusX = 4;
    RadiusY = 4;
  }
  $rect2 = New-Object CodeFactory.RectData -Property @{
    Name = "rect2";
    StyleDataName = $rectStyle1.Name;
    X = 20;
    Y = 20;
    Width = 100;
    Height = 50;
    RadiusX = 5;
    RadiusY = 5;
  }
  $rect3 = New-Object CodeFactory.RectData -Property @{
    Name = "rect3";
    StyleDataName = $rectStyle2.Name;
    X = 40;
    Y = 40;
    Width = 140;
    Height = 70;
    RadiusX = 8;
    RadiusY = 8;
  }   
  $script:shapes = @(
    $rect1;
    $rect2;
    $rect3 )
  $shapeboardDataCsCode = Import-CodeTemplate $PSScriptRoot\..\CsCode\ShapeboardData.cs
  Add-Type -Language CSharp $shapeboardDataCsCode
  $script:shapeboard = New-Object CodeFactory.ShapeboardData -Property @{
    Width = 200;
    Height = 150;
  }
}
$OutDir = "$PSScriptRoot\Export"
New-Item -ItemType Directory -Force -Path $OutDir | Out-Null
$svg = Export-FileFromTemplate $PSScriptRoot\rect.svg.template $code $OutDir\rect.svg

Result

The generated SVG file code corresponds to the structure defined in the template, after code expansion:

<svg xmlns="http://www.w3.org/2000/svg"
  viewBox="0 0 200 150">
  <defs>
    <style type="text/css">
      <![CDATA[
        rect.rectStyle1{
          fill: #FFA500;
          stroke: #28282A;
          stroke-width: 2;
        }
        rect.rectStyle2{
          fill: #F5331F;
          stroke: #28282A;
          stroke-width: 2;
        }
      ]]>
    </style>
  </defs>
  <rect 
    x='0' 
    y='0' 
    width='200' 
    height='150'
    fill='#FFCC4D'/>
  <rect 
    class='rectStyle1' 
    x='10'
    y='10'
    width='80'
    height='40'
    rx='4'
    ry='4'/>
  <rect 
    class='rectStyle1' 
    x='20'
    y='20'
    width='100'
    height='50'
    rx='5'
    ry='5'/>
  <rect 
    class='rectStyle2' 
    x='40'
    y='40'
    width='140'
    height='70'
    rx='8'
    ry='8'/>
</svg>

The generated SVG file is viewable in a browser:

PowerShell : SVG code generation

Indentation management

Because of loops use in the template and of interactions with code expansion, it becomes more difficult to control the indentation of the generated file.

Therefore, the Export-FileFromTemplate command defines indentation management functions :

Aliases allow a concise implementation of the template, which is now left-aligned:

$(i0)<svg xmlns="http://www.w3.org/2000/svg"
$(i+)viewBox="0 0 $($shapeboard.Width) $($shapeboard.Height)">
$(i=)<defs>
$(i+)<style type="text/css">
$(i+)<![CDATA[
$(i+)$(foreach ($style in $styles){"
$(i=)$($style.Target).$($style.Name){
$(i+)fill: $($style.Fill);
$(i=)stroke: $($style.Stroke);
$(i=)stroke-width: $($style.StrokeThickness);
$(i-)}`r`n"})
$(i-)]]>
$(i-)</style>
$(i-)</defs>
$(i=)<rect 
$(i+)x='0' 
$(i=)y='0' 
$(i=)width='$($shapeboard.Width)' 
$(i=)height='$($shapeboard.Height)'
$(i=)fill='#FFCC4D' />
$(i-)$(foreach ($rect in $shapes){"
$(i=)<rect 
$(i+)class='$($rect.StyleDataName)' 
$(i=)x='$($rect.X)'
$(i=)y='$($rect.Y)'
$(i=)width='$($rect.Width)'
$(i=)height='$($rect.Height)'
$(i=)rx='$($rect.RadiusX)'
$(i=)ry='$($rect.RadiusY)'/>
$(i-)`r`n"})
$(i0)</svg>

Summary

Here we have generated an SVG scene composed of several rectangles, and solved indentation issues. In future articles, we will discuss in particular the following topics:



Powered by the Perspective WebApp - © Olivier Dewit - Lyon, Paris, France - Legal informations