SvgGraphicsHtmlId.vb
''
'' This code is part of Document Solutions for Imaging demos.
'' Copyright (c) MESCIUS inc. All rights reserved.
''
Imports System
Imports System.IO
Imports System.Drawing
Imports System.Collections.Generic
Imports System.Linq
Imports System.Numerics
Imports GrapeCity.Documents.Drawing
Imports GrapeCity.Documents.Text
Imports GrapeCity.Documents.Imaging
Imports GrapeCity.Documents.Svg
Imports GCTEXT = GrapeCity.Documents.Text
Imports GCDRAW = GrapeCity.Documents.Drawing

'' This example shows how to create an SVG from scratch,
'' grouping visually related elements and assigning unique
'' HTML IDs to the groups, so that each group can be found
'' and manipulated from JavaScript code (e.g. some elements
'' of a drawing can be hidden or shown in JavaScript, etc).
'' This sample renders an arch similar to that in SvgGraphicsArch,
'' but assigns separate IDs to:
'' - the background;
'' - the arch drawing;
'' - measurements lines.
Public Class SvgGraphicsHtmlId
    Public ReadOnly Property DefaultMime As String
        Get
            Return Util.MimeTypes.SVG
        End Get
    End Property

    Public Function GenerateImageStream(
            ByVal targetMime As String,
            ByVal pixelSize As Size,
            ByVal dpi As Single,
            ByVal opaque As Boolean,
            Optional ByVal sampleParams As String() = Nothing) As Stream

        If targetMime <> Util.MimeTypes.SVG Then
            Throw New Exception("This sample only supports SVG output format.")
        End If

        Dim background As Color = Color.PaleGoldenrod,
            line As Color = Color.FromArgb(11, 83, 69),
            arc As Color = Color.FromArgb(22, 160, 133),
            fill As Color = Color.FromArgb(255, 171, 145),
            marks As Color = Color.DarkGray,
            text As Color = Color.Black,
            textBack As Color = Color.Cornsilk

        Dim Inch = dpi

        '' Text format for labels:
        Dim tf = New TextFormat() With {
            .Font = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "FreeSerif.ttf")),
            .FontSize = Inch / 6,
            .ForeColor = text
        }

        '' Arc bounding rectangle:
        Dim rc = New RectangleF(0, 0, Inch * 4, Inch * 4.8F)
        '' Transform to center the drawing:
        Dim transform = Matrix3x2.CreateTranslation(pixelSize.Width / 2.0F - rc.Width / 2, pixelSize.Height / 2.0F - rc.Height / 2)
        '' A document for each layer:
        Dim svgs = New List(Of GcSvgDocument)()

        '' In a loop (from 0 to 2), draw content that belongs to the desired
        '' current layer on a graphics, then convert that graphics to a temp GcSvgDocument
        '' and save it in a list:
        For i As Integer = 0 To 2
            Using g As New GcSvgGraphics(pixelSize.Width, pixelSize.Height)
                If i = 0 Then
                    '' Background:
                    g.FillRectangle(New RectangleF(0, 0, g.Width, g.Height), background)
                ElseIf i = 1 Then
                    '' Arch and text label:
                    g.Transform = transform
                    DrawArch(g, rc, rc.Height * 0.3F, rc.Width * 0.08F, line, arc, fill)
                    g.DrawString("ARCH", tf, rc, TextAlignment.Center, ParagraphAlignment.Center, False)
                    g.Transform = Matrix3x2.Identity
                ElseIf i = 2 Then
                    '' Measurement lines:
                    g.Transform = transform
                    Dim w = Inch / 8
                    Dim pen = New GCDRAW.Pen(marks)

                    '' Width line/label:
                    Dim txt = $"{(rc.Width / Inch):F}"""
                    Dim s = g.MeasureString(txt, tf)
                    Dim d = s.Height * 1.5F
                    g.DrawLine(rc.Left, rc.Top - d, rc.Right, rc.Top - d, pen)
                    g.DrawLine(rc.Left, rc.Top - d, rc.Left + w, rc.Top - d - w, pen)
                    g.DrawLine(rc.Left, rc.Top - d, rc.Left + w, rc.Top - d + w, pen)
                    g.DrawLine(rc.Right, rc.Top - d, rc.Right - w, rc.Top - d - w, pen)
                    g.DrawLine(rc.Right, rc.Top - d, rc.Right - w, rc.Top - d + w, pen)

                    Dim rcTxt = New RectangleF(rc.Left + rc.Width / 2 - s.Width / 2, rc.Top - d - s.Height / 2, s.Width, s.Height)
                    rcTxt.Inflate(2, 2)
                    g.FillRectangle(rcTxt, textBack)
                    g.DrawString(txt, tf, rcTxt, TextAlignment.Center, ParagraphAlignment.Center, False)

                    '' Height line/label:
                    txt = $"{(rc.Height / Inch):F}"""
                    s = g.MeasureString(txt, tf)
                    d = s.Width
                    g.DrawLine(rc.Left - d, rc.Top, rc.Left - d, rc.Bottom, pen)
                    g.DrawLine(rc.Left - d, rc.Top, rc.Left - d - w, rc.Top + w, pen)
                    g.DrawLine(rc.Left - d, rc.Top, rc.Left - d + w, rc.Top + w, pen)
                    g.DrawLine(rc.Left - d, rc.Bottom, rc.Left - d - w, rc.Bottom - w, pen)
                    g.DrawLine(rc.Left - d, rc.Bottom, rc.Left - d + w, rc.Bottom - w, pen)

                    rcTxt = New RectangleF(rc.Left - d - s.Width / 2, rc.Top + rc.Height / 2 - s.Height / 2, s.Width, s.Height)
                    rcTxt.Inflate(2, 2)
                    g.FillRectangle(rcTxt, textBack)
                    g.DrawString(txt, tf, rcTxt, TextAlignment.Center, ParagraphAlignment.Center, False)
                    g.Transform = Matrix3x2.Identity
                End If
                '' Convert the layer to a GcSvgDocument and add it to the list:
                svgs.Add(g.ToSvgDocument())
            End Using
        Next

        '' Create the resulting SVG, add each of the temp documents
        '' into a separate group with unique ID that can be used
        '' to find and manipulate it:
        Dim svg = New GcSvgDocument()
        For i As Integer = 0 To svgs.Count - 1
            Dim tsvg = svgs(i)
            Dim group = New SvgGroupElement() With {
                .ID = $"myId{i}"
            }
            While tsvg.RootSvg.Children.Count > 0
                Dim e = tsvg.RootSvg.Children(0)
                tsvg.RootSvg.Children.RemoveAt(0)
                group.Children.Add(e)
            End While
            svg.RootSvg.Children.Add(group)
        Next
        svg.RootSvg.ViewBox = New SvgViewBox(0, 0, pixelSize.Width, pixelSize.Height)

        Dim ms = New MemoryStream()
        svg.Save(ms)
        ms.Seek(0, SeekOrigin.Begin)
        Return ms
    End Function

    Private Sub DrawArch(g As GcGraphics, rc As RectangleF, harc As Single, wd As Single, line As Color, arch As Color, fill As Color)
        Dim path = g.CreatePath()
        '' Insides filler (start from bottom left, to clockwise):
        path.BeginFigure(rc.Left + wd, rc.Bottom - wd)
        path.AddLine(rc.Left + wd, rc.Top + harc)
        path.AddArc(New ArcSegment() With {
            .ArcSize = ArcSize.Small,
            .Point = New PointF(rc.Right - wd, rc.Top + harc),
            .RotationAngle = 0,
            .Size = New SizeF(rc.Width / 2.0F - wd, harc - wd),
            .SweepDirection = SweepDirection.Clockwise
        })
        path.AddLine(rc.Right - wd, rc.Bottom - wd)
        path.EndFigure(FigureEnd.Closed)
        g.FillPath(path, fill)
        path.Dispose()

        '' Arc outlines (start from bottom left, to clockwise):
        path = g.CreatePath()
        path.BeginFigure(rc.Left, rc.Bottom)
        path.AddLine(rc.Left, rc.Top + harc)
        path.AddLine(rc.Left + wd, rc.Top + harc)
        path.AddLine(rc.Left + wd, rc.Bottom - wd)
        path.EndFigure(FigureEnd.Closed)
        path.BeginFigure(rc.Left, rc.Top + harc)
        path.AddArc(New ArcSegment() With {
            .ArcSize = ArcSize.Small,
            .Point = New PointF(rc.Right, rc.Top + harc),
            .RotationAngle = 0,
            .Size = New SizeF(rc.Width / 2.0F, harc),
            .SweepDirection = SweepDirection.Clockwise
        })
        path.AddLine(rc.Right - wd, rc.Top + harc)
        path.AddArc(New ArcSegment() With {
            .ArcSize = ArcSize.Small,
            .Point = New PointF(rc.Left + wd, rc.Top + harc),
            .RotationAngle = 0,
            .Size = New SizeF(rc.Width / 2.0F - wd, harc - wd),
            .SweepDirection = SweepDirection.CounterClockwise
        })
        path.EndFigure(FigureEnd.Closed)
        path.BeginFigure(rc.Right, rc.Top + harc)
        path.AddLine(rc.Right, rc.Bottom)
        path.AddLine(rc.Right - wd, rc.Bottom - wd)
        path.AddLine(rc.Right - wd, rc.Top + harc)
        path.EndFigure(FigureEnd.Closed)
        path.BeginFigure(rc.Right, rc.Bottom)
        path.AddLine(rc.Left, rc.Bottom)
        path.AddLine(rc.Left + wd, rc.Bottom - wd)
        path.AddLine(rc.Right - wd, rc.Bottom - wd)
        path.EndFigure(FigureEnd.Closed)

        g.FillPath(path, arch)
        g.DrawPath(path, New GCDRAW.Pen(line, 2))

        path.Dispose()
    End Sub
End Class