This started out as a need to get vector data points into CDRx4 CAD from my logic analyzer, it worked easily by making an SVG element 'polyline' with the samples of logic state. The polyline becomes 1 graphic object in CAD (easy to manipulate)
Polyline SVG for import:
Code: Select all
<svg height="200" width="500">
<polyline points=" 0,0 22.9031,0 22.9031,10 24.99491,10 24.99491,0 27.85016,0 27.85016, .... "
style="fill:none;stroke:blue;stroke-width:0.1"
/>
</svg>
See VectorGraph_Example.bas
It should be noted that SVG rendering apps ( web browsers, vector graphic CAD/viewers, online converters etc.) may not display correctly or at all some SVG elements or even not load an SVG file. I have tested only with firefox browser & some online validators/converters. Different SVG versions does not help especially with obsolete syntax like 'xlink:href' ...
We need to isolate the part that is not working & edit the SVG to test. It might be just a Ucase chr or all Lcase is needed in a name or value. skewX, preserveAspectRatio="xMidyMid" , stroke-dasharray, are a few.
SVG: (for the scope of this lib)
SVG file has a Start (size, offset) - - - Contents - - - End
The contents are typically Elements with attributes & style, groups, definitions etc...
Refer the following for detail.
https://www.w3schools.com/graphics/svg_intro.asp
https://developer.mozilla.org/en-US/doc ... troduction
I would not bother trying to digest too much of the SVG specification, it's quite intense(the links above are more helpful).
Lib specifics:
ezySVG lib takes care of the SVG line structure but you must be syntactically correct with style names & value.
please refer the example bas files & SVG reference documents. The lib does not check name/value SVG syntax.
The style is just 1 string passed to the lib, it can be literal or you programmatically set values & concatenate.
You may use leading Ucase name like Fill=green if you prefer, but it may cause some issue. You can turn on force Lcase by adding #Define L_Case at the start of bas code, this will lower any Ucase characters of style name. (just view the SVG code)
Transform attributes are handled by the lib, these can be any case. (Rotate, Scale, SkewX, SkewY, Translate, Matrix)
The commands SVG_Start & SVG_End have an optional parameter value "html", this makes the SVG 'html ready' for easy open with a web browser. This is ideal for testing or print to Vector pdf. In acrobat I can also export to raster image.
With the SVG image displayed, right click 'View Page Source' to see syntax highlighted SVG code.
To debug SVG open it in your browser, observe what is not working, 'view page source' then open the SVG in your favorite text editor (preferably with xml/html syntax colors). hack the code to get it working. If you think it's a lib issue, please report.
If you have a SVG code snippet that should be working, try pasting into a html 'tryit' editor (& set values accordingly)
ezySVG lib has limitations in what can be done with SVG in comparison to SVG's vast capability.It is fairly easy to add new features & if significant could be ezySVG_2.
Most functions(sub's actually) were made by copy/paste existing sub & edit specifics.
ezySVG.bi V0.92 2024-02-15
Code: Select all
' ezySVG.bi
' Make SVG from Freebasic code ToniG Create: 2023.12.20
' File Version V0.92.2 2024-02-17
'This lib creates SVG elements, it is minimal & can be expanded to include additional functionality.
'Supported Elements:
' Line, Polyline, Polygon, Text, Rectangle, Circle, Elipse, Path, Image
'Supported Attributes:
' Many (to name a few... Fill, Stroke, Font-Family, Font-Size, Font-Weight, Font-Style)
' Transform - Rotate, Scale, Translate, SkewX, SkewY, Matrix(not tested)
' Transform-Origin (minimal tested)
'Special function:
' Quadratic Curve, Quadratic Curve Multi, SVG Group, Text on Path, Gradient fill
' DropShadow, GaussianBlur, SVG Comment, SVG_CRLF, SVG_RAW
'Notes:
' Some SVG functionality(transform, +other) may only work in a web browser (or capable viewer).
' Import to CAD may need to keep simple as possible or explicity create elements. Test & see what works.
' Use an online SVG converter to make vector cad (AI, EPS, PDF)
' For now the Element co-ordinates & size are Integer, for screen rendering
' if want to use dp precision then as Single needed.
'USAGE: Refer example bas files & SVG reference info.
'-----------------------------------
' Can use Ucase or Lcase for style strings as the lib will convert to Lcase. (except some specific Ucase requirements)
' Setting the style string with fixed values can be done with just 1 string eg. " stroke=rgb(0,0,0), stroke-width=0.5"
' to add variables for style attribute value(parameter) use eg. "stroke-width=" +Str(VarValue)
'
' To rotate a path, create the path points in a virtual bounding box (Min Max X&Y values) then use the mid point XY
' in the Transform=rotate(R,X,Y) Its not easy to resolve XY mid from complex path values. (SVG renderers do it though)
'-----------------------------------
' Changes: Since V0.10
' V0.12 2024-02-07 Change Group parameter to Style set = Group Start, Style Null = Group End
' V0.13 2024-02-10 Fixed Bug in transform Case Else (Element attr killed if Transform active)
' V0.90 2024-02-10 Add Text on Path, Gradient fill.
' V0.91 2024-02-15 Add Drop Shadow filter, change style separator from"_" to "__".
' Add code to escape "&" --> "&" in text strings only.
' Fix Var type PolyBB & rename PolyBBox
' Fix 'File path check' in Sub SVG_Image (filename only/Full path/online resource)
' V0.92 2024-02-15 Add GaussianBlur, change blur param to Single (also for drop shadow)
' V0.92.1 2024-02-16 Change order of SVG_Qbezier parameters to [x1,x2, Qx,Qy, x2,y2,...] to be consistent with "path points"
' V0.92.2 2024-02-17 Change SVG_Qbezier to use SVG_Path sub, Add CRLF indenting for SVGpath string.
' Add optional parameter 7 "xmlns" to SVG_Start, some minor fixes
'
'ToDoo:
' 1. ...
'Issues:
' 1. There May be an issue with Style string left part processing for non Transform attributes
'-----------------------------------
Declare Sub SVG_Start(SVGoutFile As String, SVG_SizeX As Long, SVG_SizeY As Long, Offset_X As integer=0, Offset_Y As integer=0, HTML_ON As String="", SVGstr As String="")
Declare Sub SVG_End(HTML_ON As String="")
Declare Sub SVG_PolyLine(SVGpoints As String, ByVal StyleSVG As String="", RotateVal As Integer=0, StyleFmt As UByte=1)
Declare Sub SVG_Line(X1 As Long, Y1 As Long, X2 As Long, Y2 As Long, ByVal StyleSVG As String="", RotateVal As Integer=0, StyleFmt As UByte=1)
Declare Sub SVG_Group(ByVal StyleSVG As String="")
Declare Sub SVG_Text(X As Long, Y As Long, TXTstr As String, ByVal StyleSVG As String="", RotateVal As Integer=0, StyleFmt As UByte=1)
Declare Sub SVG_Rect(X As Long, Y As Long, W As Long, H As Long, ByVal StyleSVG As String="", RotateVal As Integer=0, StyleFmt As UByte=1)
Declare Sub SVG_Circle(Cx As Long, Cy As Long, R As Long, ByVal StyleSVG As String="", RotateVal As Integer=0, StyleFmt As UByte=1)
Declare Sub SVG_Ellipse(Cx As Long, Cy As Long, Rx As Long, Ry As long, ByVal StyleSVG As String="", RotateVal As Integer=0, StyleFmt As UByte=1)
Declare Sub SVG_Polygon(SVGpoints As String, ByVal StyleSVG As String="", RotateVal As Integer=0, StyleFmt As UByte=1)
Declare Sub SVG_Qbezier(X1 As Long, Y1 As Long, X2 As Long, Y2 As Long, QX As Long, QY As Long, ByVal StyleSVG As String="", RotateVal As Integer=0, StyleFmt As UByte=1)
' Obsolete Declare Sub SVG_QbezierM(ByVal QbezStr As String, ByVal StyleSVG As String="", StyleFmt As UByte=1)
Declare Sub SVG_Path(ByVal SVGpathStr As String, ByVal StyleSVG As String="", RotateVal As Integer=0, StyleFmt As UByte=1)
Declare Sub SVG_TextPath(Path_ID As String, PathPoints As String, Path_Style As String, TXTstr As String, Text_Style As String, Strt_Pos As UByte=10, ShowPath As Integer=1)
Declare Sub SVG_GradientL(Grad_ID As String, Color_1 As String, Color_2 As String, Stop1 As Integer, Stop2 As Integer, X1pc As Integer, X2pc As Integer, Y1pc As Integer, Y2pc As Integer)
Declare Sub SVG_DropShadow(DS_ID As String, Color_1 As String, DX As Integer=10, DY As Integer=10, Blur As Single=2, feOffset As Integer= -20, feSize As Integer=180)
Declare Sub SVG_GaussianBlur(DS_ID As String, DX As Integer=10, DY As Integer=10, Blur As Single=2, feOffset As Integer= -20, feSize As Integer=180)
Declare Sub SVG_Image(X As Long, Y As Long, W As Long, H As Long, ByVal KeepAspect As String="", ByVal ImgPathFile As String, RotateVal As Integer=0, StyleFmt As UByte=1)
Declare Sub SVG_Comment(TXTstr As String, LFCR As UByte=0)
Declare Sub SVG_CRLF(n_ As Ubyte =1)
Declare Sub SVG_RAW(TextIn As String)
Declare Function SVG_StyleRet1(ByVal AttVal_1 As String="", ByVal AttVal_2 As String="", ByVal AttVal_3 As String="", ByVal AttVal_4 As String="", ByVal AttVal_5 As String="") As String
Declare Function SVG_StyleRet2(ByVal AttName_1 As String="", ByVal AttValu_1 As Single=0, ByVal AttName_2 As String="", ByVal AttValu_2 As Single=0, _
ByVal AttName_3 As String="", ByVal AttValu_3 As Single=0, ByVal AttName_4 As String="", ByVal AttValu_4 As Single=0) As String
Declare Function SVG_GetPolyMid(byVal PolyPts As String, PolyBBox() As Long) As Integer
'Internal functions (not for main program use)
Declare Function FormatStyle(ByVal StyleSVG As String, ByVal Xs As Integer, ByVal Ys As Integer, ByVal StyleFmt As Ubyte) As String
Declare Function FormatStyle2(ByVal StyleSVG As String, ByVal Xs As Integer, ByVal Ys As Integer, ByVal StyleFmt As UByte, Byval Part As Ubyte) As String
Declare Function FindAndChr(String1 As String) As String
Dim Shared As Ubyte SVG_Fnum ' SVG File Number
#Define CR_LF Chr(13,10)
#Define DQ Chr(34)
Sub SVG_Start(SVGoutFile As String, SVG_SizeX As Long, SVG_SizeY As Long, Offset_X As Integer = 0, Offset_Y As Integer = 0, HTML_ON As String = "", SVGstr As String="")
Dim As String HTML_head
HTML_head = "<!DOCTYPE html>" +CR_LF + _ ' easier to open for browser
"<html>" +CR_LF + _
"<body>" +CR_LF
SVG_Fnum = FreeFile
If UCase(Trim(HTML_ON)) = "HTML" Then SVGoutFile += ".html"
Open SVGoutFile for Output As #SVG_Fnum
If UCase(Trim(HTML_ON)) = "HTML" Then Print #SVG_Fnum, HTML_head
'SVG
Print #SVG_Fnum, "<svg";
Print #SVG_Fnum, " width="; DQ; Str(SVG_SizeX); DQ ;
Print #SVG_Fnum, " height="; DQ; Str(SVG_SizeY); DQ ;
Print #SVG_Fnum, " viewbox=" +DQ +Str(Offset_X) +"," +Str(Offset_Y) +"," +Str(SVG_SizeX) +"," +Str(SVG_SizeY)+DQ +" " +SVGstr;
Print #SVG_Fnum, ">"
End Sub
Sub SVG_End(HTML_ON As String = "")
Dim As String HTML_End
HTML_End = CR_LF +"</body>" +CR_LF _
+"</html>"
Print #SVG_Fnum, "</svg>"
If UCase(Trim(HTML_ON)) = "HTML" Then Print #SVG_Fnum, HTML_End
Close SVG_Fnum
End Sub
' With Style set is Group start, with Style NULL(or less than 6 chrs) = Group End
Sub SVG_Group(ByVal Style As String = "")
Dim As String TmpStr 'RetSep(1 To 2)
If Len(Trim(Style)) < 6 Then Style = ""
If Style <> "" Then
TmpStr = "<g" +CR_LF +FormatStyle(Style, 0, 0, 0)
Print #SVG_Fnum, TmpStr +CR_LF +">"
Else
Print #SVG_Fnum, "</g>" +CR_LF ' group end
EndIf
End Sub
' Alternate Group End
Sub SVG_GroupEnd()
Print #SVG_Fnum, "</g>" +CR_LF ' group end
End Sub
Sub SVG_Rect(X As Long, Y As Long, W As Long, H As Long, ByVal StyleSVG As String="", RotateVal As Integer=0, StyleFmt As UByte=1)
Dim As UByte Pos1
Dim As String Indent1, ElemAttr1, ElementStr1, ElemAttr2, TmpStr
Indent1 = "" : If StyleFmt = 0 Then Indent1 = " " '
ElementStr1 = Indent1 +"<rect"
ElemAttr1 = " x=" +DQ +Str(X) +DQ +" y=" +DQ +Str(Y) +DQ +" width=" +DQ +Str(W) +DQ +" height=" +DQ +Str(H) +DQ
If RotateVal <> 0 Then ElemAttr2 = " transform=""rotate(" +Str(RotateVal) +"," +Str(X+W/2) +"," +Str(Y+H/2) +")"""
ElementStr1 &= ElemAttr1 + ElemAttr2 ' Rotate replaces x y with a translate(x,y)
If StyleSVG <> "" Then TmpStr = FormatStyle(StyleSVG, X, Y, StyleFmt)
Print #SVG_Fnum, ElementStr1; TmpStr; "/>" '+ CR_LF
End Sub
Sub SVG_PolyLine(SVGpoints As String, ByVal StyleSVG As String="", RotateVal As Integer=0, StyleFmt As UByte=1)
Dim As UByte Pos1
Dim As Long PolyBBox(1 To 10) ' polygon bounding box(MinMax & CTR)
Dim As String Indent1, ElemAttr1, ElementStr1, ElemAttr2, TmpStr
Indent1 = "" : If StyleFmt = 0 Then Indent1 = " " '
ElementStr1 = Indent1 +"<polyline points= " '< change this for other element type & edit ElemAttr1, ElemAttr2
ElemAttr1 = DQ+ SVGpoints +DQ
SVG_GetPolyMid(SVGpoints, PolyBBox()) ' find centre
If RotateVal <> 0 Then
ElemAttr2 = " transform=""rotate(" +Str(RotateVal) +"," +Str(PolyBBox(1)) +"," +Str(PolyBBox(2)) +")"""
End If
Print #SVG_Fnum, ElementStr1 +ElemAttr1' +CR_LF
TmpStr = FormatStyle(StyleSVG, PolyBBox(1), PolyBBox(2), StyleFmt)
Print #SVG_Fnum, ElemAttr2 +TmpStr; "/>" '+ CR_LF
End Sub
Sub SVG_Polygon(SVGpoints As String, ByVal StyleSVG As String="", RotateVal As Integer=0, StyleFmt As UByte=1)
Dim As UByte Pos1
Dim As Long PolyBBox(1 To 10) ' polygon bounding box(MinMax & CTR)
Dim As String Indent1, ElemAttr1, ElementStr1, ElemAttr2, TmpStr
Indent1 = "" : If StyleFmt = 0 Then Indent1 = " " '
ElementStr1 = Indent1 +"<polygon points= "
ElemAttr1 = DQ+ SVGpoints +DQ
SVG_GetPolyMid(SVGpoints, PolyBBox()) ' find centre
If RotateVal <> 0 Then
ElemAttr2 = " transform=""rotate(" +Str(RotateVal) +"," +Str(PolyBBox(1)) +"," +Str(PolyBBox(2)) +")"""
End If
Print #SVG_Fnum, ElementStr1 +ElemAttr1' +CR_LF
TmpStr = FormatStyle(StyleSVG, PolyBBox(1), PolyBBox(2), StyleFmt)
Print #SVG_Fnum, ElemAttr2 +TmpStr; "/>" '+ CR_LF
End Sub
Sub SVG_Line(X1 As Long, Y1 As Long, X2 As Long, Y2 As Long, ByVal StyleSVG As String="", RotateVal As Integer=0, StyleFmt As UByte=1)
Dim As UByte Pos1
Dim As String Indent1, ElemAttr1, ElementStr1, ElemAttr2, TmpStr
Indent1 = "" : If StyleFmt = 0 Then Indent1 = " " : StyleFmt = 2
ElementStr1 = Indent1 +"<line"
ElemAttr1 = " x1=" +DQ +Str(X1) +DQ +" y1=" +DQ +Str(Y1) +DQ + " x2=" +DQ +Str(X2) +DQ +" y2=" +DQ +Str(Y2) +DQ
If RotateVal <> 0 Then ElemAttr2 = " transform=""rotate(" +Str(RotateVal) +"," +Str(X1) +"," +Str(Y1) +")"""
ElementStr1 &= ElemAttr1 + ElemAttr2 '
If StyleSVG <> "" Then TmpStr = FormatStyle(StyleSVG, X1, Y1, StyleFmt) ' X1 Y1 = element pos for rotate
Print #SVG_Fnum, ElementStr1; TmpStr; "/>" '+ CR_LF
End Sub
Sub SVG_Circle(Cx As Long, Cy As Long, R As Long, ByVal StyleSVG As String="", RotateVal As Integer=0, StyleFmt As UByte=1)
Dim As UByte Pos1
Dim As String Indent1, ElemAttr1, ElementStr1, ElemAttr2, TmpStr
Indent1 = "" : If StyleFmt = 0 Then Indent1 = " " '
ElementStr1 = Indent1 +"<circle"
ElemAttr1 = " cx=" +DQ +Str(Cx) +DQ +" cy=" +DQ +Str(Cy) +DQ + " r=" +DQ +Str(R) +DQ
ElementStr1 &= ElemAttr1 + ElemAttr2 ' Rotate enabled for consistency
TmpStr = FormatStyle(StyleSVG, Cx, Cy, StyleFmt)
Print #SVG_Fnum, ElementStr1; TmpStr; "/>" '+ CR_LF
End Sub
Sub SVG_Ellipse(Cx As Long, Cy As Long, Rx As Long, Ry As long, ByVal StyleSVG As String="", RotateVal As Integer=0, StyleFmt As UByte=1)
Dim As UByte Pos1
Dim As String Indent1, ElemAttr1, ElementStr1, ElemAttr2, TmpStr
Indent1 = "" : If StyleFmt = 0 Then Indent1 = " " '
ElementStr1 = Indent1 +"<ellipse"
ElemAttr1 = " cx=" +DQ +Str(Cx) +DQ +" cy=" +DQ +Str(Cy) +DQ +" rx=" +DQ +Str(Rx) +DQ +" ry=" +DQ +Str(Ry) +DQ
If RotateVal <> 0 Then ElemAttr2 = " transform=""rotate(" +Str(RotateVal) +"," +Str(Cx) +"," +Str(cy) +")"""
ElementStr1 &= ElemAttr1 + ElemAttr2 ' Rotate replaces x y with a translate(x,y)
If StyleSVG <> "" Then TmpStr = FormatStyle(StyleSVG, Cx, Cy, StyleFmt)
Print #SVG_Fnum, ElementStr1; TmpStr; "/>" '+ CR_LF
End Sub
Sub SVG_Text(X As Long, Y As Long, TXTstr As String, ByVal StyleSVG As String="", RotateVal As Integer=0, StyleFmt As UByte=1)
Dim As UByte Pos1
Dim As String Indent1, ElemAttr1, ElementStr1, ElemAttr2, TmpStr
TXTstr = FindAndChr(TXTstr)
Indent1 = "" : If StyleFmt = 0 Then Indent1 = " " '
ElementStr1 = Indent1 +"<text"
ElemAttr1 = " x=" +DQ +Str(X) +DQ +" y=" +DQ +Str(Y) +DQ
If RotateVal <> 0 Then ElemAttr2 = " transform=""rotate(" +Str(RotateVal) +"," +Str(X) +"," +Str(Y) +")"""
ElementStr1 &= ElemAttr1 + ElemAttr2
TmpStr = FormatStyle(StyleSVG, X, Y, StyleFmt) 'X Y need not for text ??
Print #SVG_Fnum, ElementStr1; " "; TmpStr; ">"; TXTstr; "</text>" '+ CR_LF
End Sub
Sub SVG_TextPath(Path_ID As String, PathPoints As String, Path_Style As String, TXTstr As String, Text_Style As String, Strt_Pos As UByte=10, ShowPath As Integer=1)
Dim As String Def_Str, Text_Str, Indent1 = " "
TXTstr = FindAndChr(TXTstr)
Def_Str = "<defs>" +CR_LF +" <path id=" +DQ +Path_ID +DQ +" d=" +DQ +PathPoints +DQ +" "
Def_Str &= FormatStyle(Path_Style, 0, 0, 1) +"></path>" +CR_LF + "</defs>" +CR_LF
If ShowPath = 1 Then Def_Str &= " <use href=" +DQ +"#" +Path_ID +DQ +"></use>"
Text_Str = "<text " +FormatStyle(Text_Style, 0, 0, 1) +">" +CR_LF
Text_Str &= Indent1 +"<textPath href=" +DQ +"#" +Path_ID +DQ +" startOffset=" +DQ +Str(Strt_Pos) +"%"">" +CR_LF
Text_Str &= Indent1 +Indent1 +TXTstr +CR_LF
Text_Str &= Indent1 +"</textPath>" +CR_LF
Text_Str &= "</text>" +CR_LF
Print #SVG_Fnum, Def_Str
Print #SVG_Fnum, Text_Str
End Sub
' Quadratic Bezier curve (using path)
Sub SVG_Qbezier(X1 As Long, Y1 As Long, QX As Long, QY As Long, X2 As Long, Y2 As Long, ByVal StyleSVG As String="", RotateVal As Integer=0, StyleFmt As UByte=1)
Dim As String ElemAttr1, TmpStr = ""
ElemAttr1 = "M " +Str(X1) +"," +Str(Y1) +" Q " +Str(QX) +"," +Str(QY) +" " +Str(X2) +"," +Str(Y2)
If RotateVal <> 0 AndAlso InStr(LCase(StyleSVG), "rotate") = 0 Then ' check if rotate set
TmpStr = "Rotate=(" +Str(RotateVal) +"," +Str(X1) +"," +Str(Y1) +")"
If InStr(StyleSVG, "__") = 0 Then TmpStr &= "__" Else TmpStr &= " " ' check if left part exist
EndIf
StyleSVG = TmpStr +StyleSVG
SVG_Path( ElemAttr1, StyleSVG, RotateVal, StyleFmt)
End Sub
' Path Element
Sub SVG_Path(ByVal SVGpathStr As String, ByVal StyleSVG As String="", RotateVal As Integer=0, StyleFmt As UByte=1)
Dim As String Indent1 ="", ElemAttr1 = "", ElemAttr2, ElementStr1, TmpStr
Dim As Integer Pos1 = 0
ElementStr1 = Indent1 +"<path d=" +DQ '+CR_LF
TmpStr = SVGpathStr
Pos1 = InStr(TmpStr, CR_LF)
Do While Pos1 <> 0 ' Indent path points if CRLF in PathString
ElemAttr1 &= Indent1 +Left(TmpStr, Pos1-1)
TmpStr = Right(TmpStr, Len(TmpStr)-(Pos1+1))
Pos1 = InStr(TmpStr, CR_LF)
Indent1 = CR_LF +Space(9)
If Pos1 = 0 AndAlso Len(TmpStr) > 1 Then ElemAttr1 &= Indent1 +TmpStr' +CR_LF
Loop
If TmpStr = SVGpathStr Then ElemAttr1 = SVGpathStr ' If no CRLF
ElementStr1 &= ElemAttr1 +DQ
ElemAttr2 = FormatStyle(StyleSVG, 0, 0, StyleFmt) ' transform rotate is default ViewBox 0,0
Print #SVG_Fnum, ElementStr1; CR_LF; ElemAttr2 +"/>"
End Sub
' Linear Gradient
Sub SVG_GradientL(Grad_ID As String, Color_1 As String, Color_2 As String, Stop1 As Integer, Stop2 As Integer, X1pc As Integer, X2pc As Integer, Y1pc As Integer, Y2pc As Integer)
Dim As String Def_Str, Text_Str, Indent1 = " "
Def_Str = " <defs>" +CR_LF
Def_Str &= Indent1 +"<linearGradient id=" +DQ + Grad_ID +DQ
Def_Str &= " x1=" +DQ +Str(X1pc) +"%" +DQ
Def_Str &= " x2=" +DQ +Str(X2pc) +"%" +DQ
Def_Str &= " y1=" +DQ +Str(Y1pc) +"%" +DQ
Def_Str &= " y2=" +DQ +Str(Y2pc) +"%" +DQ +">" +CR_LF
Def_Str &= Indent1 +Indent1 +"<stop offset=" +DQ +Str(Stop1) +"%" +DQ +" stop-color=" +DQ +Color_1 +DQ +" />" +CR_LF
Def_Str &= Indent1 +Indent1 +"<stop offset=" +DQ +Str(Stop2) +"%" +DQ +" stop-color=" +DQ +Color_2 +DQ +" />" +CR_LF
Def_Str &= Indent1 +"</linearGradient>" +CR_LF
Def_Str &= " </defs>" +CR_LF
Print #SVG_Fnum, Def_Str
End Sub
' DropShadow
Sub SVG_DropShadow(DS_ID As String, Color_1 As String, DX As Integer=10, DY As Integer=10, Blur As Single=2, feOffset As Integer= -20, feSize As Integer=180)
Dim As String Def_Str, Text_Str, Indent1 = " "
Def_Str = " <defs>" +CR_LF
Def_Str &= Indent1 +"<filter id=" +DQ + DS_ID +DQ
Def_Str &= " x=" +DQ +Str(feOffset) +"%" +DQ
Def_Str &= " y=" +DQ +Str(feOffset) +"%" +DQ
Def_Str &= " width=" +DQ +Str(feSize) +"%" +DQ
Def_Str &= " height=" +DQ +Str(feSize) +"%" +DQ +">" +CR_LF
Def_Str &= Indent1 +Indent1 +"<feDropShadow" +" dx=" +DQ +Str(DX) +DQ +" dy=" +DQ +Str(DY) +DQ _
+" stdDeviation=" +DQ +Str(Blur) +DQ +" flood-color=" +DQ +Str(Color_1) +DQ +" />" +CR_LF
Def_Str &= Indent1 +"</filter>" +CR_LF
Def_Str &= " </defs>" +CR_LF
Print #SVG_Fnum, Def_Str
End Sub
' GaussianBlur
Sub SVG_GaussianBlur(DS_ID As String, DX As Integer=0, DY As Integer=0, Blur As Single=2, feOffset As Integer= -20, feSize As Integer=150)
Dim As String Def_Str, Text_Str, Indent1 = " "
Def_Str = " <defs>" +CR_LF
Def_Str &= Indent1 +"<filter id=" +DQ + DS_ID +DQ
Def_Str &= " x=" +DQ +Str(feOffset) +"%" +DQ
Def_Str &= " y=" +DQ +Str(feOffset) +"%" +DQ
Def_Str &= " width=" +DQ +Str(feSize) +"%" +DQ
Def_Str &= " height=" +DQ +Str(feSize) +"%" +DQ +">" +CR_LF
Def_Str &= Indent1 +Indent1 +"<feGaussianBlur" +" stdDeviation=" +DQ +Str(Blur) +DQ +" result=" +DQ + DS_ID +DQ +" />" +CR_LF
Def_Str &= Indent1 +Indent1 +"<feOffset " +"dx=" +DQ +Str(DX) +DQ +" dy=" +DQ +Str(DY) +DQ +" />" +CR_LF
Def_Str &= Indent1 +"</filter>" +CR_LF
Def_Str &= " </defs>" +CR_LF
Print #SVG_Fnum, Def_Str
End Sub
' <defs>
' <filter id="shadow1" x="-20%" y="-20%" width="140%" height="140%">
' <feGaussianBlur stdDeviation="1.5" result="shadow1"/>
' <feOffset dx="-6" dy="6"/>
' </filter>
' </defs>
Sub SVG_Image(X As Long, Y As Long, W As Long, H As Long, ByVal KeepAspect As String="", ByVal ImgPathFile As String, RotateVal As Integer=0, StyleFmt As UByte=1)
Dim As String Indent1, ElemAttr1, ElementStr1, ElemAttr2, TmpStr
ElementStr1 = Indent1 +"<image href=" +DQ
If InStr(ImgPathFile,"http") = 0 Then ' local file
ElementStr1 &= "file:"
If InStr(ImgPathFile,":") <> 0 Or InStr(ImgPathFile,"\") <> 0 Then ElementStr1 &= "//" ' with full path
End If
ElementStr1 &= ImgPathFile +DQ
ElemAttr1 = " x=" +DQ +Str(X) +DQ +" y=" +DQ +Str(Y) +DQ +" width=" +DQ +Str(W) +DQ +" height=" +DQ +Str(H) +DQ
If RotateVal <> 0 Then ElemAttr2 = " transform=""rotate(" +Str(RotateVal) +"," +Str(X+W/2) +"," +Str(Y+H/2) +")" +DQ
ElementStr1 &= ElemAttr1 ' Rotate replaces x y with a translate(x,y)
If KeepAspect <> "" Then ElemAttr2 &= " preserveAspectRatio=" +DQ +Trim(KeepAspect) +DQ 'FormatStyle(StyleSVG, X, Y, StyleFmt)
Print #SVG_Fnum, ElementStr1; ElemAttr2; TmpStr; "/>"
End Sub
' ref
'<image href="file:mdn_logo_only_color.png" x="550" y="280" width="150" height="200"
'<image href="file://d:\Data\FBedit\DataGraph\mdn_logo_only_color.png" x="600" y="300" width="150" height="150"/>
'<image href="https://i.postimg.cc/qqT64fy9/mdn-logo-only-color.png" x="550" y="280" width="150" height="200"
' Misc. Subs
'----------------------------------------------------------
Sub SVG_Comment(TXTstr As String, LFCR As UByte=0)
If LFCR > 0 Then Print #SVG_Fnum, ""
Print #SVG_Fnum, "<!-- "; TXTstr; " -->"
End Sub
Sub SVG_CRLF(n_ As Ubyte =1)
Dim As UByte Lp1
For Lp1 = 1 To n_ : Print #SVG_Fnum, : Next
End Sub
' make SVG line from TextIn (must be Valid SVG syntax string)
Sub SVG_RAW(TextIn As String)
Print #SVG_Fnum, TextIn
End Sub
' Find un-escaped "&" & escape it
Function FindAndChr(String1 As String) As String
Dim As Integer Pos1 = 0
Dim As String TempStr = "", EscAnd = "&" '"&"
Pos1 = InStr(String1,"&")
If Pos1 = 0 Or Mid(String1,Pos1,5) = EscAnd Then ' no "&" or it escaped
TempStr = String1
Else
TempStr = Left(String1,Pos1-1) +EscAnd +Right(String1, Len(String1)-Pos1)
EndIf
Function = TempStr
End Function
' Utility Functions
'---------------------------------------------------------
' Get the XY Center & XY Min Max for polygon points
Function SVG_GetPolyMid(byVal PolyPts As String, PolyBBox() As Long) As Integer
Dim As UInteger Lp1, MaxVal_X, MaxVal_Y, MinVal_X = &hFFFFFF, MinVal_Y = &hFFFFFF
Dim As String Chr1, ValStr, Xval, Yval
Xval = "" : Yval = ""
For Lp1 = 1 To Len(PolyPts)
Chr1 = Mid(PolyPts, Lp1,1)
If (Chr1 <> " " AndAlso Chr1 <> ",") Then ValStr &= Chr1 ' get the number chr's (only chr(32) whitespace allowed)
If Lp1 = Len(PolyPts) Andalso ValStr <> "" Then chr1 = " "
' Get X val
If Chr1 = "," AndAlso Len(ValStr) > 0 Then
Xval = ValStr : ValStr = "" ': XvalFound = TRUE
If MaxVal_X < Val(Xval) Then MaxVal_X = Val(Xval)
If MinVal_X > Val(Xval) Then MinVal_X = Val(Xval)
Yval = ""
EndIf
' Get Y val
If Chr1= " " AndAlso Len(ValStr) > 0 AndAlso Len(Xval) Then' AndAlso Xval > 0 Then ' Get Y val
Yval = ValStr : ValStr = "" ': YvalFound = TRUE
If MaxVal_y < Val(Yval) Then MaxVal_Y = Val(Yval)
If MinVal_y > Val(Yval) Then MinVal_Y = Val(Yval)
Xval = ""
EndIf
Next
' Array Return ByRef - Bounding Box
PolyBBox(1) = MinVal_X + ((MaxVal_X - MinVal_X) / 2) ' Mid X
PolyBBox(2) = MinVal_Y + ((MaxVal_Y - MinVal_Y) / 2) ' Mid Y
PolyBBox(3) = MinVal_X : PolyBBox(4) = MaxVal_X ' MinMax X
PolyBBox(5) = MinVal_Y : PolyBBox(6) = MaxVal_Y ' MinMax Y
End Function
' ---------- Warning: Dont mix Style Left & Right parts when calling these 2 Functions ---------
' Convert separate style strings from program to single style string. (might be useful)
' use for inserting variables in style string.
' Return Style string from "String" +Str(Value),"String" +Str(Value), ...
Function SVG_StyleRet1(ByVal AttVal_1 As String="", ByVal AttVal_2 As String="", ByVal AttVal_3 As String="", ByVal AttVal_4 As String="", ByVal AttVal_5 As String="") As String
Dim As String AttributeVal(1 to 6) = {AttVal_1, AttVal_2, AttVal_3, AttVal_4, AttVal_5,""}
Dim As String StyleSVG = ""
Dim As UByte Lp1
For Lp1 = 1 To 5
If Lp1 <> 1 AndAlso AttributeVal(Lp1) <> "" Then StyleSVG &= ", "
If AttributeVal(Lp1) <> "" Then StyleSVG &= AttributeVal(Lp1)
Next
SVG_StyleRet1 = StyleSVG
End Function
' Return Style string from "Str",Valu,"Str",Valu, ... (might be useful)
Function SVG_StyleRet2(ByVal AttName_1 As String="", ByVal AttValu_1 As Single=0, ByVal AttName_2 As String="", ByVal AttValu_2 As Single=0, _
ByVal AttName_3 As String="", ByVal AttValu_3 As Single=0, ByVal AttName_4 As String="", ByVal AttValu_4 As Single=0) As String
Dim As String AttributeName(1 to 4) = {AttName_1, AttName_2, AttName_3, AttName_4}
Dim As Single AttributeValu(1 to 4) = {AttValu_1, AttValu_2, AttValu_3, AttValu_4}
Dim As String StyleSVG = ""
Dim As UByte Lp1
For Lp1 = 1 To 5
If Lp1 <> 1 AndAlso AttributeName(Lp1) <> "" Then StyleSVG &= ", "
If AttributeName(Lp1) <> "" Then StyleSVG &= AttributeName(Lp1) + Str(AttributeValu(Lp1))' +", "
Next
SVG_StyleRet2 = StyleSVG
End Function
'------------------------------------------------
' Formatting Attributes & Values for Transform & Style
'=====================================================================
' Separate Transform & Style, format each then return formatted string
Private Function FormatStyle(ByVal Style As String, ByVal Xs As Integer = 0, ByVal Ys As Integer = 0, ByVal StyleFmt As Ubyte = 0) As String
Dim As UByte Pos1, Part
Dim As String TransF, Style1, TmpStr
'Style =
Pos1 = Instr(Style , "__")
If Pos1 > 0 Then
TransF = left(Style, Pos1-1) ' Transform part
Style1 = Right(Style, (Len(Style)-(Pos1+1))) ' Style part
Part = 1 : TmpStr = FormatStyle2(TransF, Xs, Ys, 1, Part) ' Transform(& other) part
Else
Style1 = Style
EndIf
Part = 2 : TmpStr & = FormatStyle2(Style1, Xs, Ys, StyleFmt, Part) ' Style part
FormatStyle = TmpStr
'Print #5, "Style ret L+R--"; TmpStr ' DEBUG
End Function
Const LB = "(" : Const RB = ")"
' Format Style (or Element attributes)
Private Function FormatStyle2(ByVal StyleSVG As String, ByVal Xs As Integer = 0, ByVal Ys As Integer = 0, _
ByVal StyleFmt As UByte = 1, Byval Part As Ubyte) As String
Dim As String Chr1, TmpStr, Attr_Add, TranslateOriginPart
Dim As UByte BrktL, CSF1, CSF2, StrLen, Lp1, Lp2, Pos1, PartCnt1
Dim As String StylePart(20,3), RotatePart, SkewXpart, SkewYpart, ScalePart, TranslatePart, MatrixPart
If StyleSVG = "" Then Exit Function
BrktL = 0 : CSF1 = 1 : CSF2 = 1 : PartCnt1 = 1
' Find CS Values (CSV)
StrLen = Len(StyleSVG)
For Lp1 = 1 To StrLen
Chr1 = Mid(StyleSVG, Lp1,1)
If Chr1 = "(" Then BrktL = Lp1 '
If Chr1 = ")" AndAlso BrktL > 0 Then BrktL = 0 '
If (Chr1= "," Andalso BrktL = 0) Then CSF2 = LP1 ' Ignore "," between brackets
If Lp1 = StrLen And Right(StyleSVG,1) <> "," Then CSF2 = LP1+1 ' Get the last CS Val
If CSF2 > CSF1 Then
TmpStr = Trim(Mid(StyleSVG, CSF1, CSF2-CSF1)) ' Extract CSV data
Pos1 = Instr(TmpStr , "=")
' Store style in array
#IfDef L_case ' Attrib part
StylePart(PartCnt1,1) = LCase(left(TmpStr, Pos1-1)) ' Force Lcase left of =
#Else
StylePart(PartCnt1,1) = left(TmpStr, Pos1-1) ' MixedCase
#EndIf
StylePart(PartCnt1,2) = Right(TmpStr, (Len(TmpStr)-Pos1)) ' Value part
TmpStr = ""
PartCnt1 +=1
CSF1 = CSF2+1
EndIf
Next
If Part = 1 Then ' Format Element values or Transform=" "
If PartCnt1 < 1 Then Exit Function
'Print #5, "StyleSVG In=" +StyleSVG ' DEBUG
Attr_Add = ""
For Lp1 = 1 To PartCnt1-1
'Remove value Brakets
Pos1 = InStr(StylePart(Lp1,2),"(")
If Pos1 > 0 Then Mid(StylePart(Lp1,2), Pos1,1) = " "
Pos1 = InStr(StylePart(Lp1,2),")")
If Pos1 > 0 Then Mid(StylePart(Lp1,2), Pos1,1) = " "' : StylePart(Lp1,2) = Trim(StylePart(Lp1,2))
StylePart(Lp1,2) = Trim(StylePart(Lp1,2))
'Print #5, "Part1_Len= " +Str(Len(StylePart(Lp1,2))) ' DEBUG
'Print #5, "Part1_2= " +StylePart(Lp1,1); " _ " +StylePart(Lp1,2) : #EndIf' DEBUG
'TmpStr = StylePart(Lp1,1)
TmpStr = LCase(StylePart(Lp1,1))
Select Case TmpStr 'StylePart(Lp1,1)
Case Is = "scale"
ScalePart = "translate(" +Str(Xs) +"," +Str(Ys) +") " _
+"scale(" +Str(StylePart(Lp1,2)) +") " _
+"translate(" +Str(-Xs) +"," +Str(-Ys) +") "
Case Is = "rotate"
RotatePart = "rotate(" +StylePart(Lp1,2) +"," +Str(Xs) +"," +Str(Ys) +") "
If InStr(StylePart(Lp1,2)," ") OrElse InStr(StylePart(Lp1,2),",") Then ' rotate point is in rotate val
RotatePart = "rotate(" +StylePart(Lp1,2) +") "
EndIf
Case Is = "skewx"
SkewXpart = "skewX(" +StylePart(Lp1,2) +") " 'must be Ucase "X"
Case Is = "skewy"
SkewYpart = "skewY" +StylePart(Lp1,2) +") " ' " "Y"
Case Is = "matrix"
MatrixPart = "matrix(" +StylePart(Lp1,2) +") " ' not tested yet 2024.01.06
Case Is = "translate"
TranslatePart = "translate(" +StylePart(Lp1,2) +") "
Case Is = "transform-origin"
TranslateOriginPart = "transform-origin" +StylePart(Lp1,2) ' Not working yet, puts inside main " "
Case Else ' Non style attributes, but not part of Transform=" "
'Print #5, "Not Transform attr = " +TmpStr 'DEBUG
If StylePart(Lp1,1) = "rx" Then Attr_Add &= " rx=" +DQ +Str(StylePart(Lp1,2)) +DQ
If StylePart(Lp1,1) = "ry" Then Attr_Add &= " ry=" +DQ +Str(StylePart(Lp1,2)) +DQ
' For additional element attributes, add them here...
End Select
Next
' Concatenate in order [SVG Transform evaluates Left <-- Right]
TmpStr = ""
TmpStr= TranslatePart +RotatePart +TranslateOriginPart +SkewXpart +SkewYpart +ScalePart +MatrixPart
If TmpStr <> "" Then TmpStr= " transform=" +DQ +Trim(TmpStr) +DQ
FormatStyle2 = Attr_Add +TmpStr
Exit Function '< already formatted (is fixed type)
EndIf
' Build style string 'Look at using following code block with transform=... ? (Part = 1)
StyleSVG = "" : PartCnt1 -=1
For Lp1 = 1 To PartCnt1
'Print #5, "STpart_2= " +StylePart(Lp1,2)
' Enable use of brackets or "," in Dasharray value input eg. (3,5) or (3 5) or 3 5
Chr1 = "" : TmpStr = ""
If InStr(StylePart(Lp1,1), "stroke-dasharray") AndAlso InStr(StylePart(Lp1,2), "(") Then
For Lp2 = 1 To Len(StylePart(Lp1,2))
Chr1 = Mid(StylePart(Lp1,2),Lp2,1)
If Chr1 = "," Then Chr1 = " "
If Chr1 = ")" Then Exit For ' we are done
If Chr1 <> "(" Then TmpStr &= Chr1
Next
StylePart(Lp1,2) = TmpStr
EndIf
' Format style
Select Case StyleFmt
Case 0 ' [<g >] Group style format (each attribute on newline)
StyleSVG &= " " + StylePart(Lp1,1) + "=""" + StylePart(Lp1,2) + """" '+ CR_LF
If Lp1 <> PartCnt1 Then StyleSVG &= CR_LF
Case 1 ' [: ;] style format
If Lp1 = 1 Then StyleSVG = " style="""
StyleSVG &= StylePart(Lp1,1) + ":" + StylePart(Lp1,2)
If Lp1 <> PartCnt1 Then StyleSVG &= ";" : Else StyleSVG &= """" :EndIf
Case 2 ' [=" "] DQ style format
StyleSVG &= " " +StylePart(Lp1,1) + "=""" + StylePart(Lp1,2) + """"
End Select
Next
FormatStyle2 = StyleSVG
End Function
#Undef CR_LF
#UnDef DQ
' ---------END-------------------
Test ezySVG_1.bas
Code: Select all
' TestSVG_1.bas - Freebasic Code
'Example for ezySVG Library
' This code is just a list of examples to show usage, it's not meant to be a structured program.
' Makes SVG in the app run folder.
' To see result, click on the output .html file or drop on browser. 'View Page Source' to check/debug SVG code
' All drawing is done in the SVG ViewBox that sits on the virtual canvas default top left, the size & offset is set in 'SVG_Start'
' The SVG contains Elements (Line, rect, circle etc...) & they each have parameters(values) for position, size etc.
' Elements also have other attributes & style attributes.
' Many style attributes are optional & often have a default value (some may result in an Element part not rendered.)
' Be mindful tha not all SVG render apps are equal, what works in 1 may not in another.
' To set style attributes you refer to SVG style reference, same when using named colors (CSS)
' Typically all Style attributes are lower case, however you may use first letter Ucase for clarity but a few need to be case sensitive
' such as stroke-dasharray must be Lcase(tested in fireFox), some have Ucase parts. Just lookup a reference to be sure.
' Most values can have space or comma separator, stroke=rgb(130 130 130) stroke=rgb(130,130,130) <- both are valid in ezySVG lib
' Only parameters with more than 1 value have brackets & "," or " " separators.
' with the exception of stroke-dasharray=(3,5) or =(3 5) or =3 5
' Rotate(in style string) has 2 modes Rotate=-12 uses default Element point Rotate=(-12,100,220) uses points set.
' Sometimes when drawing an Element or making changes, it seems to disapear but it could just be outside the viewbox
' somewhere on the canvas (canvas has no size limit) or there is a typo.
' Color values(RGB) are string either #C0FFE9 or RGB(255,89,130)
' Element position & size values are number(long), Element attributes are string, Style is a string
' Style string has optional left part (non style attributes) with separator "__"(Double Underscore).
' These are for Transform & additionakl Element attributes.
' V0.90 2024-02-15
#Define L_Case ' Use to turn on Lcase formatting of SVG Style Names (must be before #Include "ezySVG.bi")
#Include "ezySVG.bi"
Dim As String TempStr, StyleStr
Dim As UInteger VboxSizeX, VboxSizeY, Lp1
Dim As Uinteger FillCol, LineCol, LineW, X, Y
Dim As String SVGstyle, HexRGB1, HexRGB2
Dim As string PolyPoints, PathPts, TxtStr
Dim As Integer PolyMid(1 To 10) ' polygon virtual bounding box(MinMax & CTR)
Dim As Integer XS, YS, Rote, SkewXval, SkewYval
' Open "debug2.txt" For Output As #5
VboxSizeX = 1000
VboxSizeY = 500
Const CR_LF = Chr(13,10)
Const DQ = Chr(34)
Const html_ = "html" ' choose "svg in html"
'Const html_ = "" ' or "svg"
' SVG_Start("TestSVG_1.SVG", VboxSizeX, VboxSizeY, -500, -250, "html") ' with offset
SVG_Start("TestSVG_1.SVG", VboxSizeX, VboxSizeY, 0, 0, html_)
'SVG_Start("TestSVG_1.SVG", VboxSizeX, VboxSizeY, 0, 0)
' SVG_Rect(-20, -20, 20, 20, "rx=5, ry=5_fill=silver, stroke=black, stroke-width=2") ' test offset
' Rectangle to fit SVG ViewBox
StyleStr = "Fill=Silver, stroke=black, stroke-width=2"', fill-opacity=1, stroke-opacity=1"
SVG_Comment(" This rect fills the ViewBox", 1)
SVG_Rect(0, 0, VboxSizeX, VboxSizeY, StyleStr)
SVG_CRLF '<- put a newline in SVG code to improve structure (no effect on graphic)
SVG_Line(VboxSizeX/2, 0, VboxSizeX/2, VboxSizeY, "stroke=rgb(130 130 130), stroke-width=1, stroke-dasharray=(8,12)")
SVG_Line(0, VboxSizeY/2, VboxSizeX, VboxSizeY/2, "stroke=rgb(130,130,130), stroke-width=1, stroke-dasharray=(8 12)")
SVG_CRLF
' Text at ViewBox X centre
TempStr = "ezySVG Test 2024.02.11"
SVG_Text(VboxSizeX/2, 25, TempStr, "font-family=verdana, font-size=18px, Font-Weight=bold, fill=navy, text-anchor=middle",,1)
' various Text styles
SVG_Text(25, VboxSizeY/2, "Rotate Left (middle anchor)", "text-anchor=middle",-90)
SVG_Text(VboxSizeX-25, VboxSizeY/2, "Rotated Right (middle anchor)", "font-family=verdana, fill=purple, text-anchor=middle",90)
SVG_Text(520, 75, "Text - Outline only", "font-family=verdana, font-size=24px, Font-Weight=bold, Fill=none, Stroke-width=1, stroke=black")
SVG_Text(10, VboxSizeY-10, "If viewing this graphic in a web browser, view page source to see SVG code(syntax color'd)", "font-style=italic ,font-size=12px")
SVG_Text(1,10, "0,0", "Font-style=italic ,font-size=12px")
SVG_Text(501,260, "500,250", "Font-style=italic ,font-size=12px")
SVG_CRLF
SVG_Comment(" some lines...")
' 2nd line is rotated 5deg.
SVG_Line(10, 40, 200, 40, "stroke=green, stroke-width=2")
SVG_Line(600, 40, 700, 40, "stroke=green, stroke-width=2",5)
'-----------------------------
' Apply style to a group
SVG_Comment(" This is a style group", 1)
StyleStr = "stroke=blue, stroke-width=2, stroke-dasharray=(8,2)"
SVG_Group(StyleStr) ' group start
For Lp1 = 60 To 100 Step 10
If Lp1 = 80 Then StyleStr = "Stroke=Purple, stroke-width=3, stroke-dasharray=0" : Else StyleStr = ""
SVG_Line(10, Lp1, 200, Lp1, StyleStr,,0) ' set the Style format "0" adds indent
Next
SVG_Line(10, 110, 200, Lp1,"rotate=5, scale=1.5__Stroke=yellow, Stroke-Width=1, stroke-dasharray=(3,5)",,0)' override group style for this element
SVG_Group("End") ' group close - End or Null param
SVG_Text(10, 125, "6 lines above are in a style group, 2 lines have style override", "font-size=12px",5)
SVG_Line(230, 40, 475, 90, "stroke=red, stroke-width=5")
'-----------------------------
' Rectangle rounded corners & fill transparancy 60%
StyleStr = "fill=#C0E2D5, stroke=black, stroke-width=2, fill-opacity=0.6"' , stroke-opacity=1"
SVG_Rect(250, 40, 200, 50, StyleStr)
LineW = 1 : LineCol = 24000 ' LineCol might come from a color map
FillCol = 764345
HexRGB1 = "#" + Hex(FillCol,6)
HexRGB2 = "#" + Hex(LineCol,6) '
'Print #5, "FillCol "; FillCol; " "; HexRGB1
SVG_Ellipse(80, 180, 25, 15, "fill=#E2C0D5, Stroke=RGB(00,175,255), Stroke-Width=" +Str(LineW+2) )
SVG_Ellipse(80, 220, 25, 15, "fill=#E2C0D5, Stroke=RGB(00,75,255), Stroke-Width=2",45) ' rotated 45deg
SVG_Circle(160, 200, 25, "fill=#E2C0D5, Stroke=RGB(00,00,255), Stroke-Width=3")
SVG_Circle(200, 200, 30, "fill=none, stroke=black, stroke-width=2, Stroke-opacity=0.5") ' outline only
SVG_CRLF
'-------------------------------------------------------
' These lines have variables for each attribute value
SVGstyle = "stroke=" +HexRGB2 +", Fill=" +HexRGB1 +", stroke-width=" +Str(LineW)
' SVGstyle = "stroke=#" +Hex(LineCol,6) +", Fill=#" +Hex(FillCol,6) +", stroke-width=" +Str(LineW)
'------------------------------------------------------
' Using SVG_StyleRet1() may be easier...
' !!! Dont mix Style Left__right parts
SVGstyle = SVG_StyleRet1("stroke=" +HexRGB2, "Fill=" +HexRGB1, "stroke-width=" +Str(LineW))
'SVG_Line(45, 373, 500, 373, SVGstyle)
SVG_Rect(950, 45, 30,8, SVGstyle)
' Using SVG_StyleRet2() may be easier... but not many attributes
' !!! Dont mix Style Left__right parts
' SVGstyle = SVG_StyleRet2("Rotate=", Rote, "Skew=", SkewXval, "stroke-width=", LineW, "Stroke-Opacity=", 0.6)
SVGstyle = SVG_StyleRet2("stroke-width=", LineW, "Stroke-Opacity=", 0.6)
SVG_Line(45, 371, 500, 371, SVGstyle +", stroke=red")
SVG_Line(45, 372, 500, 372, SVGstyle +", stroke=green") '< Note the comma in string for additional style
SVG_Line(45, 373, 500, 373, SVGstyle +", stroke=blue")
'------------------------------------------------------
SVG_Text(950, 30, " Some tiny text to see", "font-size=3px") ' SVG does not do multiline text !!! (CRLF not work)
SVG_Text(950, 35, " Zoom in to read","font-size=3px")
SVG_Text(950, 40, " SVG Doesnt do MultiLine Text!","font-size=3px")
Rote = 20
PolyPoints = "350,100 379,181 469,161 397,215 423,301 350,250 277,301 303,215 231,161 321,181"
SVG_Polygon(PolyPoints, "fill=none, stroke=red, stroke-width=1, stroke-dasharray=(2,3)")
SVG_Polygon(PolyPoints, "fill=none, stroke=blue, stroke-width=1, stroke-dasharray=(4,8)",Rote)
SVG_Polygon(PolyPoints, "Rotate=-12__fill=none, stroke=green, stroke-width=1, stroke-dasharray=(4,4)") ',Rote-8
'Polygon & PolyPoints are very similar. PP need extra point to close, Both need fill=none for line only.
SVG_Text(350, 340, "PolyGon (rotated)", "font-size=13px")
SVG_Comment(" Poly Line", 1)
'PolyLine
SVG_PolyLine("300,400 350,450 400,400 300,400", "Rotate=(2,350,450)__stroke=blue, stroke-width=2")
' In above fill is not specified so default is fill=black
' Rotate origin is specified
SVG_PolyLine("300,400 350,450 400,400 300,400", "Rotate=90__stroke=yellow, stroke-width=1, fill=none")
' Rotate origin is not specified (uses polypoints xy mid)
SVG_Text(400, 465, "PolyLine", "font-size=13px")
' Testing PolyMid
SVG_GetPolyMid(PolyPoints, PolyMid()) ' get polygon/polyline centre & XY min/max (bounding box)
XS = 40 : YS = 40
SVG_Rect(PolyMid(1)-XS/2, PolyMid(2), XS, YS, StyleStr, 45) '< put a rectangle in the polygon centre
SVG_Circle(PolyMid(1), PolyMid(2), 5, "fill=none, stroke=black, stroke-width=1, Stroke-opacity=0.9")
SVG_Comment(" Quad Bezier curve",1 ) ' 3 points (X1, Y1, X2, Y2, QX, QY)
'/'
Rote = 15
StyleStr = "stroke=white, stroke-width=3, fill=none"
SVG_Qbezier(520, 150, 560, 30, 620, 150, "stroke=black, stroke-width=2, fill=purple, Fill-opacity=0.4", Rote)
SVG_Qbezier(520, 150, 570, 150, 620, 150, StyleStr, Rote)
'/
' SVG_Qbezier(520, 150, 560, 30, 620, 150, "stroke=black, stroke-width=2, fill=purple, Fill-opacity=0.4")
' SVG_Qbezier(520, 150, 570, 150, 620, 150, "Rotate=(12,520,150)__stroke=white, stroke-width=3, fill=none")
' Str(Y2-(Y2-Y1/2)
''SVG_Path("M620,150 Q650,70 680,150" ,StyleStr) ' see Test Qbezier.bas
SVG_Text(520, 190, "Quad Bezier curve (1 control point)", "font-size=13px")
SVG_Text(520, 205, "Rotated 15deg. with fill & Baseline", "font-size=13px") ' Note: & = "&" (& is illegal chr)
SVG_CRLF
SVG_Rect(700, 100, 80, 40, "rx=8, ry=8__fill=darkblue, stroke=green, stroke-width=3") ' Note the radius attributes
SVG_Rect(800, 100, 80, 40, "rx=8, ry=8, SkewX=10__fill=none, stroke=black, stroke-width=1") ' in Transform part (left of separator "__")
SVG_Comment("SVG Paths", 1) ' SVG Path (point values would typically be produced from geometric/math code)
PathPts = " M 213,7" +CR_LF _
+" c -32-14-74,0-88,30" +CR_LF _
+" C 110,5,67-9,36,6" +CR_LF _
+" z"
PathPts = "M 213,7" +" c -32 -14 -74,0 -88,30" +" C 110,5,67 -9,36,6" +" z" ' z = line to start point
SVG_Path(PathPts, "Fill=none, Stroke=black")
' This path has the same xy points but is translated(moved) to Y= 420 * has rotate applied
SVG_Path("M 213,7 c -32 -14 -74,0 -88,30 C 110,5,67 -9.5,36,6", "Rotate=(15,213,7), translate=(0,440)__Fill=none, Stroke=blue")
SVG_Text(50, 465, "Path(2x C.Bezier curve)", "font-size=13px")
' Path points are like polyline & polygon points in that the previous segment end point is the next segment start point.
' this can be a bit hard to "see" the segment values when the type changes(line to bezier) especially Cubic beier.
' In above there are 3 line segments followed by 2 Quadratic(1 ctrl pt) bezier curves.
' Typically Ucase type(M L Q) is explicit point & Lcase type(m l q) is relative to previous point.
' BZstrt BZctrl BZEnd
' Moveto Lineto Lineto Lineto BZstrt BZctrl BZEnd
PathPts = "M 50,300 L 100,300 120,325 150,325 Q 175,300 200,325 225,350 250,325" 'z" (z is line to start)
SVG_Path(PathPts, "Fill=none, Stroke=black")
SVG_Text(50, 355, "Path(3x lines, 2x Qbezier curve", "font-size=13px")
SVG_Path("M 500,220 L 500, 280 M 470,250 L 530,250", "Fill=none, Stroke=black") ' crosshairs
SVG_Path("M 100,400 Q 175,375 200,400 175,425 100,400", "Fill=none, Stroke=blue")
SVG_CRLF
' preserveAspectRatio xMinyMin, xMaxyMax not working !
' Raster Image
SVG_Comment(" Raster Image in SVG",1)
Dim As String FilePath = "" '"d:\Data\FBedit\DataGraph\" ' full path
Dim As String FileName
' choose your image source Filename (local or online)
' FileName = "mdn_logo_only_color.png" ' file name only (img in Test ezySVG_1exe run folder)
FileName = "https://i.postimg.cc/qqT64fy9/mdn-logo-only-color.png" ' online res
SVG_Rect(550, 280, 150, 200, "Fill=none, Stroke=grey, stroke-dasharray=(1,3)") ' Just for ref.
SVG_Image(550, 280, 150, 200, , FilePath +FileName, 0) 'Param 5: KeepAspect is default, or "none" to fit XY
SVG_Text(550, 475, "Raster image", "font-size=13px")
' Text on Path
TxtStr = "Text Along a Path - Cool"
SVG_Comment(" Text on a Path",1)
PathPts = "M 700,325 Q 750,300 800,325 850,345 900,325"
SVG_TextPath("Path1" , PathPts, "Fill=none, Stroke=blue, stroke-width=1, stroke-dasharray=(2,2)", TxtStr, "font-size=17px",8)
' Drop Shadow
SVG_Comment(" Drop Shadow effect",1)
SVG_DropShadow("DSf1", "grey", 5, 10, 2)
SVG_PolyLine("700,230 750,230 770,210 728,210 700,230", "filter=url(#DSf1), stroke=brown, stroke-width=1, fill=navy, fill-opacity=0.75")
' GaussianBlur
SVG_Comment(" GaussianBlur effect",1)
SVG_GaussianBlur("GB1", 2, 2, 0.35) '(filter ID, Xoffset, Yoffset, blur)
' applied to a text Element to create DropShadow
SVG_Group("text-anchor= middle, font-size=24px font-weight=bold, font-family=verdana")
SVG_Text(820, 270, "TextShadow using GaussianBlur", "filter=url(#GB1), fill=#505050",,0) '< This is the shadow
SVG_Text(820, 270, "TextShadow using GaussianBlur", "fill=navy",,0)
SVG_Group
' Alternately we can set filter X Y offset=0 & position the shadow text
' Linear Gradient
SVG_Comment(" Linear Gradient Fill",1)
SVG_GradientL("Grad1", "blue", "red", 0, 100, 0, 100, 0, 0)
SVG_DropShadow("DSf1", "grey", 12, 12, 1.5)
SVG_Ellipse(850, 400, 100, 50, "fill=url(#Grad1), filter=url(#DSf1)",,2)
SVG_Circle(850, 400, 30, "fill=url(#Grad1), stroke=black, stroke-width=2, Stroke-opacity=0.5",,2)
' The chr case for ID name must match. ie: "Grad1" set & use "ul(#grad1)" will fail.
' SVG_Text(750, 475, "Gradient Fill & Drop Shadow", "font-size=13px")
SVG_Text(750, 475, "Gradient Fill & Drop Shadow", "font-size=13px")
SVG_Text(825, 200, "skewX Transform", "font-size=13px")
SVG_CRLF
'SVG_End("html")
SVG_End(html_)
'SVG_End()
' Beep ' I am done
' Close #5 '< DEBUG
End
' These 2 lines result in same SVG code
' SVG_Line(600, 40, 700, 40, "stroke=green, stroke-width=2", 5) or
' SVG_Line(600, 40, 700, 40, "Rotate=5__stroke=green, stroke-width=2") note the underscore separator before style attributes.