Example 2: Basic clickable SVG shapes with fglsvgcanvas

Example using the fglsvgcanvas web component to draw basic shapes and detect mouse events.

Figure: fglsvgcanvas web component - basics

Screenshot of a program using the fglsvgcanvas web component
Form definition file svgbasics.per:
LAYOUT
GRID
{
[cv                               |fi              ]
[                                 |                ]
[                                 |                ]
[                                 |                ]
[                                 |                ]
[                                 |                ]
[                                 |                ]
[                                 |                ]
[                                 |                ]
[                                 |                ]
[                                 |                ]
[                                 |                ]
[                                 |                ]
}
END
END

ATTRIBUTES

WEBCOMPONENT cv=FORMONLY.canvas,
   COMPONENTTYPE="fglsvgcanvas",
   PROPERTIES=(
     selection = "item_selection",
     selection2 = "item_selection2",
     selection3 = "item_selection3",
     mouse_over = "item_mouse_over",
     mouse_out  = "item_mouse_out",
     mouse_event_timeout = 600,
     mouse_event_focus   = false
   ),
   SIZEPOLICY=FIXED,
   STRETCH=BOTH,
   SCROLLBARS=NONE
;
TEXTEDIT fi = FORMONLY.info,
   STRETCH=BOTH;

END
Program file svgbasics.4gl:
IMPORT util
IMPORT FGL fglsvgcanvas

DEFINE rec RECORD
           canvas STRING,
           info STRING
       END RECORD

DEFINE canvas_id SMALLINT

MAIN

    OPEN FORM f1 FROM "svgbasics"
    DISPLAY FORM f1

    CALL fglsvgcanvas.initialize()
    LET canvas_id = create_svg()
    CALL fglsvgcanvas.display(canvas_id)

    INPUT BY NAME rec.* ATTRIBUTES(UNBUFFERED)
        ON ACTION clear_info ATTRIBUTES(TEXT = "Clear info")
           LET rec.info = NULL
        ON ACTION item_selection ATTRIBUTES(DEFAULTVIEW=NO)
           CALL add_info_line("selection")
        ON ACTION item_selection2 ATTRIBUTES(DEFAULTVIEW=NO)
           CALL add_info_line("selection2")
        ON ACTION item_selection3 ATTRIBUTES(DEFAULTVIEW=NO)
           CALL add_info_line("selection3")
        ON ACTION item_mouse_over ATTRIBUTES(DEFAULTVIEW = NO)
           CALL add_info_line("mouse over")
        ON ACTION item_mouse_out ATTRIBUTES(DEFAULTVIEW = NO)
           CALL add_info_line("mouse out")
    END INPUT

    CALL fglsvgcanvas.destroy(canvas_id)
    CALL fglsvgcanvas.finalize()

END MAIN

FUNCTION create_svg() RETURNS SMALLINT

    CONSTANT CB = 1
    CONSTANT CY = 2
    CONSTANT CG = 3
    CONSTANT T1 = 4
    DEFINE root_svg om.DomNode,
           attr DYNAMIC ARRAY OF om.SaxAttributes,
           defs, g, n om.DomNode
    DEFINE cid SMALLINT

    LET cid = fglsvgcanvas.create("formonly.canvas")
    LET root_svg = fglsvgcanvas.setRootSVGAttributes( NULL,
                                   NULL, NULL,
                                   "0 0 500 500",
                                   "xMidYMid meet"
                                )
    CALL root_svg.setAttribute(SVGATT_CLASS,"root_svg")

    LET attr[CB] = om.SaxAttributes.create()
    CALL attr[CB].addAttribute(SVGATT_FILL,           "cyan" )
    CALL attr[CB].addAttribute(SVGATT_FILL_OPACITY,   "0.3" )
    CALL attr[CB].addAttribute(SVGATT_STROKE,         "blue" )
    CALL attr[CB].addAttribute(SVGATT_STROKE_WIDTH,   "5" )
    CALL attr[CB].addAttribute(SVGATT_STROKE_OPACITY, "0.3" )

    LET attr[CY] = om.SaxAttributes.create()
    CALL attr[CY].addAttribute(SVGATT_FILL,           "yellow" )
    CALL attr[CY].addAttribute(SVGATT_FILL_OPACITY,   "0.8" )
    CALL attr[CY].addAttribute(SVGATT_STROKE,         "orange" )
    CALL attr[CY].addAttribute(SVGATT_STROKE_WIDTH,   "4" )
    CALL attr[CY].addAttribute(SVGATT_STROKE_OPACITY, "0.8" )

    LET attr[CG] = om.SaxAttributes.create()
    CALL attr[CG].addAttribute(SVGATT_FILL,           "green" )
    CALL attr[CG].addAttribute(SVGATT_FILL_OPACITY,   "0.8" )
    CALL attr[CG].addAttribute(SVGATT_STROKE,         "darkGreen" )
    CALL attr[CG].addAttribute(SVGATT_STROKE_WIDTH,   "4" )
    CALL attr[CG].addAttribute(SVGATT_STROKE_OPACITY, "0.8" )

    LET attr[T1] = om.SaxAttributes.create()
    CALL attr[T1].addAttribute(SVGATT_STROKE,         "gray" )
    CALL attr[T1].addAttribute(SVGATT_STROKE_WIDTH,   "1" )
    CALL attr[T1].addAttribute(SVGATT_STROKE_LINECAP, "round" )
    CALL attr[T1].addAttribute(SVGATT_FILL,           "blue" )
    CALL attr[T1].addAttribute(SVGATT_FONT_FAMILY,    "Sans" )
    CALL attr[T1].addAttribute(SVGATT_FONT_SIZE,      "24px" )

    LET defs = fglsvgcanvas.defs( NULL )
    CALL defs.appendChild( fglsvgcanvas.styleList(
                              fglsvgcanvas.styleDefinition(".style_1",attr[CB])
                           || fglsvgcanvas.styleDefinition(".style_2",attr[CY])
                           || fglsvgcanvas.styleDefinition(".style_3",attr[CG])
                           || fglsvgcanvas.styleDefinition(".style_4",attr[T1])
                           )
                         )
    CALL root_svg.appendChild( defs )

    CALL root_svg.appendChild( fglsvgcanvas.text(30, 40,
           "Basic fglsvgcanvas example...", "style_4" ) )

    CALL root_svg.appendChild( n:=fglsvgcanvas.rect(200,200,350,150,10,10) )
    CALL n.setAttribute("id","R1")
    CALL n.appendChild(fglsvgcanvas.title("Rectangle 1"))
    CALL n.setAttribute(SVGATT_STYLE,'stroke:black;fill:orange' )

    CALL root_svg.appendChild( n:=fglsvgcanvas.circle(40,120,50) )
    CALL n.setAttribute("id","C1")
    CALL n.appendChild( fglsvgcanvas.title("Circle 1 (with mouse hovering effects)") )
    CALL n.setAttribute(SVGATT_CLASS, "style_1")
    CALL n.setAttribute(SVGATT_ONMOUSEOVER, "evt.target.setAttribute('opacity', '0.5');")
    CALL n.setAttribute(SVGATT_ONMOUSEOUT,  "evt.target.setAttribute('opacity', '1.0');")

    CALL root_svg.appendChild( n:=fglsvgcanvas.ellipse(50,400,50,30) )
    CALL n.setAttribute("id","E1")
    CALL n.appendChild( fglsvgcanvas.title("Ellipse 1 (clickable)") )
    CALL n.setAttribute(SVGATT_CLASS, "style_3")
    CALL n.setAttribute(SVGATT_ONCLICK, SVGVAL_ELEM_CLICKED)

    CALL root_svg.appendChild( n:=fglsvgcanvas.rect(400,100,150,50,5,10) )
    CALL n.setAttribute("id","R2")
    CALL n.appendChild( fglsvgcanvas.title("Rectangle 2 (with mouse hovering actions)") )
    CALL n.setAttribute(SVGATT_CLASS, "style_2")
    CALL n.setAttribute(SVGATT_ONMOUSEOVER, SVGVAL_ELEM_MOUSE_OVER)
    CALL n.setAttribute(SVGATT_ONMOUSEOUT, SVGVAL_ELEM_MOUSE_OUT)

    CALL root_svg.appendChild( g:=fglsvgcanvas.g( "G1" ) )
    CALL g.appendChild( fglsvgcanvas.title(
           "Group of elements 1 (clickable and mouse hovering actions)") )
    CALL g.setAttribute(SVGATT_ONCLICK, SVGVAL_ELEM_CLICKED)
    CALL g.setAttribute(SVGATT_ONMOUSEOVER, SVGVAL_ELEM_MOUSE_OVER)
    CALL g.setAttribute(SVGATT_ONMOUSEOUT, SVGVAL_ELEM_MOUSE_OUT)
    CALL g.appendChild( n:=fglsvgcanvas.rect(380,390,100,100,NULL,NULL) )
    CALL n.setAttribute(SVGATT_STYLE,'stroke:black;fill:none' )
    CALL g.appendChild( n:=fglsvgcanvas.rect(400,400,70,50,5,10) )
    CALL n.setAttribute(SVGATT_CLASS, "style_2" )
    CALL g.appendChild( n:=fglsvgcanvas.circle(420,450,30) )
    CALL n.setAttribute(SVGATT_CLASS, "style_3" )

    CALL root_svg.appendChild( n:=fglsvgcanvas.rect(100,150,50,80,20,20) )
    CALL n.setAttribute("id","R3")
    CALL n.appendChild( fglsvgcanvas.title(
           "Rectangle 3 (with animation, clickable and mouse hovering actions)") )
    CALL n.setAttribute(SVGATT_STYLE,'stroke:black;fill:#AA2244' )
    CALL n.setAttribute(SVGATT_ONCLICK, SVGVAL_ELEM_CLICKED)
    CALL n.setAttribute(SVGATT_ONMOUSEOVER, SVGVAL_ELEM_MOUSE_OVER)
    CALL n.setAttribute(SVGATT_ONMOUSEOUT, SVGVAL_ELEM_MOUSE_OUT)
    CALL n.appendChild( fglsvgcanvas.animateTransform("transform", "XML", "rotate",
                                                      "0 100 200", "360 200 150", NULL,
                                                      "0s", "20s", "indefinite" ) )


    RETURN cid

END FUNCTION

FUNCTION add_info_line(event STRING) RETURNS ()
    LET rec.info = rec.info, SFMT( "%1: %2 - %3",
                       CURRENT HOUR TO FRACTION(3),
                       fglsvgcanvas.getItemId(canvas_id),
                       event), "\n"
END FUNCTION