whispervis/page.go

131 lines
2.9 KiB
Go
Raw Normal View History

2018-09-06 12:15:55 +00:00
package main
import (
"bytes"
"fmt"
"github.com/divan/graphx/formats"
2018-09-06 15:37:46 +00:00
"github.com/divan/graphx/graph"
2018-09-06 12:15:55 +00:00
"github.com/divan/graphx/layout"
"github.com/gopherjs/vecty"
"github.com/gopherjs/vecty/elem"
"github.com/gopherjs/vecty/event"
"github.com/status-im/whispervis/widgets"
)
// Page is our main page component.
type Page struct {
vecty.Core
layout *layout.Layout
2018-09-17 19:11:04 +00:00
webgl *WebGLScene
2018-09-06 12:15:55 +00:00
2018-09-17 19:11:04 +00:00
loaded bool
2018-09-06 12:15:55 +00:00
loader *widgets.Loader
forceEditor *widgets.ForceEditor
2018-09-11 19:52:06 +00:00
upload *widgets.UploadWidget
2018-09-17 19:11:04 +00:00
data *graph.Graph
2018-09-06 12:15:55 +00:00
}
2018-09-11 15:33:28 +00:00
// NewPage creates and inits new app page.
2018-09-17 19:11:04 +00:00
func NewPage() *Page {
2018-09-06 15:37:46 +00:00
page := &Page{
2018-09-17 19:11:04 +00:00
loader: widgets.NewLoader(),
forceEditor: widgets.NewForceEditor(),
2018-09-06 15:37:46 +00:00
}
2018-09-11 19:52:06 +00:00
page.upload = widgets.NewUploadWidget(page.onUpload)
2018-09-17 19:11:04 +00:00
page.webgl = NewWebGLScene()
2018-09-06 15:37:46 +00:00
return page
}
2018-09-06 12:15:55 +00:00
// Render implements the vecty.Component interface.
func (p *Page) Render() vecty.ComponentOrHTML {
return elem.Body(
elem.Div(
vecty.Markup(
vecty.Class("pure-g"),
vecty.Style("height", "100%"),
),
elem.Div(
vecty.Markup(vecty.Class("pure-u-1-5")),
elem.Heading1(vecty.Text("Whisper Message Propagation")),
elem.Paragraph(vecty.Text("This visualization represents message propagation in the p2p network.")),
2018-09-11 19:52:06 +00:00
p.upload,
2018-09-06 14:43:42 +00:00
elem.Div(
vecty.Markup(
vecty.MarkupIf(!p.loaded, vecty.Style("visibility", "hidden")),
),
p.forceEditor,
2018-09-06 15:37:46 +00:00
p.updateButton(),
2018-09-06 14:43:42 +00:00
),
2018-09-06 12:15:55 +00:00
),
elem.Div(
2018-09-17 19:11:04 +00:00
vecty.Markup(
vecty.Class("pure-u-4-5"),
/*
we use display:none property to hide WebGL instead of mounting/unmounting,
because we want to create only one WebGL context and reuse it. Plus,
WebGL takes time to initialize, so it can do it being hidden.
*/
vecty.MarkupIf(!p.loaded,
vecty.Style("visibility", "hidden"),
vecty.Style("height", "0px"),
vecty.Style("width", "0px"),
),
),
p.webgl,
),
elem.Div(
vecty.Markup(
vecty.Class("pure-u-4-5"),
2018-09-06 12:15:55 +00:00
),
vecty.If(!p.loaded, p.loader),
),
),
vecty.Markup(
event.KeyDown(p.KeyListener),
event.VisibilityChange(p.VisibilityListener),
2018-09-06 12:15:55 +00:00
),
)
}
2018-09-06 15:37:46 +00:00
func (p *Page) updateButton() *vecty.HTML {
return elem.Div(
elem.Button(
vecty.Markup(
vecty.Class("pure-button"),
vecty.Style("background", "rgb(28, 184, 65)"),
vecty.Style("color", "white"),
vecty.Style("border-radius", "4px"),
event.Click(p.onUpdateClick),
),
vecty.Text("Update"),
),
)
}
func (p *Page) onUpdateClick(e *vecty.Event) {
if !p.loaded {
return
}
go p.StartSimulation()
2018-09-06 15:37:46 +00:00
}
2018-09-17 19:11:04 +00:00
// UpdateNetworkGraph updates graph and scene with new data.
func (p *Page) UpdateNetworkGraph(json []byte) error {
buf := bytes.NewBuffer(json)
data, err := formats.FromD3JSONReader(buf)
if err != nil {
return fmt.Errorf("update graph: %v", err)
}
p.data = data
config := p.forceEditor.Config()
2018-09-17 19:11:04 +00:00
p.layout = layout.NewFromConfig(data, config.Config)
go p.StartSimulation()
return nil
}