mirror of
https://github.com/status-im/whispervis.git
synced 2025-02-01 16:04:56 +00:00
85 lines
1.9 KiB
Go
85 lines
1.9 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"io"
|
|
"runtime"
|
|
|
|
"github.com/divan/graphx/graph"
|
|
"github.com/gopherjs/vecty"
|
|
)
|
|
|
|
// UpdateGraph starts graph layout simulation.
|
|
func (p *Page) UpdateGraph() {
|
|
p.loader.Reset()
|
|
p.loaded = false
|
|
vecty.Rerender(p)
|
|
|
|
config := p.forceEditor.Config()
|
|
p.loader.SetSteps(config.Steps)
|
|
for i := 0; i < config.Steps; i++ {
|
|
p.layout.UpdatePositions()
|
|
p.loader.Inc()
|
|
vecty.Rerender(p.loader)
|
|
runtime.Gosched()
|
|
}
|
|
p.loaded = true
|
|
// TODO(divan): remove previous objects
|
|
p.webgl.RemoveObjects()
|
|
p.webgl.CreateObjects(p.layout.Positions(), p.layout.Links())
|
|
|
|
vecty.Rerender(p)
|
|
}
|
|
|
|
// ApplyForces applies current forces to the objects, and runs
|
|
// a single simulation run to update positions.
|
|
func (p *Page) ApplyForces() {
|
|
fc := p.forceEditor.Config()
|
|
p.layout.SetConfig(fc.Config)
|
|
p.layout.UpdatePositions()
|
|
p.webgl.updatePositions()
|
|
p.webgl.rt.Disable()
|
|
}
|
|
|
|
// GraphFromJSON is a custom version of graphx JSON importer, as we want to use
|
|
// some additional fields (Description).
|
|
// TODO(divan): that's probably can be done better within the limits of graphx library.
|
|
func GraphFromJSON(r io.Reader) (*graph.Graph, string, error) {
|
|
// decode into temporary struct to process
|
|
var res struct {
|
|
Description string `json:"description"`
|
|
Nodes []*graph.BasicNode `json:"nodes"`
|
|
Links []*struct {
|
|
Source string `json:"source"`
|
|
Target string `json:"target"`
|
|
} `json:"links"`
|
|
}
|
|
err := json.NewDecoder(r).Decode(&res)
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
|
|
if len(res.Nodes) == 0 {
|
|
return nil, "", errors.New("empty graph")
|
|
}
|
|
|
|
// convert links IDs into indices
|
|
g := graph.NewGraphMN(len(res.Nodes), len(res.Links))
|
|
|
|
for _, node := range res.Nodes {
|
|
g.AddNode(node)
|
|
}
|
|
|
|
for _, link := range res.Links {
|
|
err := g.AddLink(link.Source, link.Target)
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
}
|
|
|
|
g.UpdateCache()
|
|
|
|
return g, res.Description, nil
|
|
}
|