Frontend Go — interacting with graphics and charts

Seán Murphy
Level Up Coding
Published in
5 min readJun 24, 2020

--

Photo by Lukas Blazek on Unsplash

In previous posts (entry point), I described how it’s possible to use Go for both frontend and backend for a toy application. This initial work was basic and I wanted to delve a little deeper. Here I report on my experience getting a (slightly) more sophisticated frontend operational using Go.

I wanted to have a basic frontend that could display chart(ish) content; initially, I considered using simple graphics as the basis for the charts, based on some observations that this can be easier than working with D3. Subsequently, I considered how interaction with Apache ECharts, a feature-rich Javascript charts library, works from Go. As with the previous posts, the frontend work was all based on vecty.

Adding charts based on SVG

I first checked out how to display SVG content within vecty. vecty itself does not (currently) have specific SVG supports, but I found a relatively new Go package— nathanhacks/svg — which focuses on providing SVG support within this context. Using this library, it was possible to generate simple line charts, pie charts and bar charts as can be seen in the video below.

As the library is still new, work is ongoing on maturing the capabilities and interfaces. The library provides basic primitives for interacting with SVG graphics based on the SVG Web API; concepts and API calls defined there map very directly to the library capabilities. One interesting aspect of the SVG model is that there is flexibility on defining which part of the co-ordinate system to display and, indeed, this can be modified dynamically to provide different visual effects such as motion and panning. This means that in principle it is possible to choose arbitrary areas of a plane on which to place the graphic and display it. This was useful when displaying a pie chart: it’s most convenient to work with the part of the plane centred on (0, 0) rather than having this point at the top left of the viewport.

Another issue which was not apparent at the outset —primarily due to my lack of SVG knowledge — was that it has a quite sophisticated path model which is used as the basis for creating all but the simplest shapes: to generate segments of a pie chart, for example, it was necessary to construct a filled path of the correct shape — see below for basic idea.

func renderSector() *vecty.HTML {  openingAngle=initialPercentage*2*math.Pi
segmentAngle=additionalPercentage*2*math.Pi
p := path.MoveTo(0, 0) x = float64(rx) * math.Cos(openingAngle)
y = -float64(ry) * math.Sin(openingAngle)
p = p.LineTo(x, y)
closingAngle = openingAngle + segmentAngle
x = float64(rx) * math.Cos(closingAngle )
y = -float64(ry) * math.Sin(closingAngle)
p = p.Arc(rx, ry, 0.0, 0, 0, x, y)
p = p.ClosePath() image := []svg.Component{
attr.Class("svg-image"),
attr.Width(300),
attr.Height(300),
attr.ViewBox(0, 0, 100, 100),
attr.Stroke("red"),
svgelem.Path(attr.Stroke("red"), attr.Fill("red"), attr.D(p)),
}
return elem.Div(
vecty.Markup(
vecty.Class("chart-panel"),
),
svg.Render(image),
)
}

Adding charts based on Apache ECharts

Having understood the basic mechanisms and the design of the SVG library, I realized that it would require quite some effort to support different chart types using this approach.

I next looked into using ECharts and considering how to use it from vecty. This was interesting to consider the specific chart integration, but also to understand the Go/Javascript integration mechanism more generally, such that arbitrary Javascript functionality could be invoked from Go.

The comprehensive go-echarts library offered a good starting point: go-echarts provides functionality to create many different chart types in Go and output HTML/Javascript to visualize the charts. A key point is that it only supports static charts: the charts and associated data are defined within the generator code and static HTML/Javascript is output — it does not (yet) provide a means to enable charts to be shown in HTML pages that are dynamically controlled via Go.

ECharts offers an extensive JS API which controls many aspects of chart interaction with two specific calls accounting for a lot of key functionality: echarts.init creates an instance of a chart in a specific container within a page and <chart>.setOptions parameterizes the chart — including chart type, chart data, legends etc — and displays it accordingly. These two functions are used by go-echarts.

To use these functions it was first necessary to create a div into which the chart could be inserted; when the divwas inserted into the page, the echarts functions noted above were called. As the raison d’etre of vecty is to support dynamic control of page content, it could not be assumed that the div was generated a priori: vecty should add content to the page when necessary. This created a small issue: the Javascript object corresponding to the div needs to be provided to the echarts.init function, but it is not certain that it exists in the page. vecty Components can handle this, providing a Mount() call as part of the interface which gets called when the Component is rendered in the page: for each chart type in this example — line chart, pie chart and bar chart, a Component was created which has functionality to call the echarts functions when the div has been inserted into the page.

After initializing echarts on the div, it was necessary to configure the chart using the setOptions call. Providing the correct input to the setOptions call required some effort — being in the Javascript world, it required a valid Javascript object, but the go-echartslibrary offered no mechanism to export the chart state into such an object. Hence, modifications to the go-echarts library were required. As these objects had to be converted to Javascript entities using the syscall/js ValueOf function, the chart options had to be in a specific format (ValueOf requires Javascript objects to be map[string]interface{} and lists to be []interface{}): hence I added a new function GenerateOptions() to the different chart types which converts the state stored within go-echarts to something that can be passed to echarts dynamically. It is worth noting that the Go structs package does a lot of the conversion work.

Demonstration

The demonstration is very simple, offering the option to show a (very) basic SVG based set of charts or a more sophisticated set of ECharts; it is possible to switch between both dynamically. The short video below shows both the installation and build process in a clean VM and the resulting output.

Video showing install process and resulting output

Final remarks

It does not answer all questions around Go/JS integration: it remains unclear if the page modifications made by the ECharts JS library could have negative implications for the Go/WASM application, with the latter having no visibility of these changes. For this simple demonstration, no negative implications have been observed, but for more complex applications, such issues could arise.

The github repo containing the content is here.

Acknowledgement: thanks to nathanhack for help on some of the SVG aspects of this work.

--

--

Tech Tinkerer, Curious Thinker(er). Lost Leprechaun. Always trying to improve.