whispervis/widgets/force_editor.go
2018-10-20 14:47:19 +02:00

95 lines
2.0 KiB
Go

package widgets
import (
"github.com/divan/graphx/layout"
"github.com/gopherjs/vecty"
"github.com/gopherjs/vecty/elem"
"github.com/gopherjs/vecty/event"
)
// DefaultForcesConfig specifies default configuration for physics simulation.
var DefaultForcesConfig = ForcesConfig{
Config: layout.DefaultConfig,
Steps: 10,
}
// ForceEditor represents forces and physics simulation configuration widget.
type ForceEditor struct {
vecty.Core
config ForcesConfig
repelling *ForceInput
spring *ForceInput
drag *ForceInput
steps *Range
apply func()
}
// ForcesConfig represents physics simulation configuration.
type ForcesConfig struct {
layout.Config
Steps int
}
// NewForceEditor creates a new ForceEditor widget.
func NewForceEditor(apply func()) *ForceEditor {
config := DefaultForcesConfig
repelling := NewForceInput("Gravity:", config.Repelling)
spring := NewForceInput("Spring:", config.SpringStiffness)
drag := NewForceInput("Drag:", config.DragCoeff)
steps := NewRange("Steps:", config.Steps)
return &ForceEditor{
config: config,
repelling: repelling,
spring: spring,
drag: drag,
steps: steps,
apply: apply,
}
}
// Render implements vecty's Component interface for ForceEditor.
func (f *ForceEditor) Render() vecty.ComponentOrHTML {
return Widget(
Header("Layout forces:"),
elem.Form(
f.repelling,
f.spring,
f.drag,
f.steps,
),
f.applyButton(),
)
}
// Config returns current forces & simulation configuration, getting values from UI.
func (f *ForceEditor) Config() ForcesConfig {
return ForcesConfig{
Steps: f.steps.Value(),
Config: layout.Config{
Repelling: f.repelling.Value(),
SpringStiffness: f.spring.Value(),
SpringLen: f.config.SpringLen,
DragCoeff: f.drag.Value(),
},
}
}
func (f *ForceEditor) applyButton() *vecty.HTML {
return elem.Div(
elem.Button(
vecty.Markup(
vecty.Class("button", "is-info", "is-small"),
event.Click(f.onClick),
),
vecty.Text("Apply"),
),
)
}
func (f *ForceEditor) onClick(e *vecty.Event) {
go f.apply()
}