2018-09-06 16:54:35 +03:00
|
|
|
package widgets
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/divan/graphx/layout"
|
|
|
|
"github.com/gopherjs/vecty"
|
|
|
|
"github.com/gopherjs/vecty/elem"
|
2018-10-19 22:10:56 +02:00
|
|
|
"github.com/gopherjs/vecty/event"
|
2018-09-06 16:54:35 +03:00
|
|
|
)
|
|
|
|
|
2018-09-20 20:43:43 +03:00
|
|
|
// DefaultForcesConfig specifies default configuration for physics simulation.
|
|
|
|
var DefaultForcesConfig = ForcesConfig{
|
|
|
|
Config: layout.DefaultConfig,
|
2018-10-19 16:41:16 +02:00
|
|
|
Steps: 10,
|
2018-09-20 20:43:43 +03:00
|
|
|
}
|
|
|
|
|
2018-09-17 22:11:04 +03:00
|
|
|
// ForceEditor represents forces and physics simulation configuration widget.
|
2018-09-06 16:54:35 +03:00
|
|
|
type ForceEditor struct {
|
|
|
|
vecty.Core
|
|
|
|
|
2018-09-17 22:11:04 +03:00
|
|
|
config ForcesConfig
|
2018-09-06 20:07:24 +03:00
|
|
|
|
2018-10-20 19:39:28 +02:00
|
|
|
repelling *ForceInput
|
|
|
|
spring *ForceInput
|
|
|
|
drag *ForceInput
|
|
|
|
steps *Range
|
|
|
|
collapsable *Collapsable
|
2018-10-19 22:10:56 +02:00
|
|
|
|
|
|
|
apply func()
|
2018-09-06 16:54:35 +03:00
|
|
|
}
|
|
|
|
|
2018-09-17 22:11:04 +03:00
|
|
|
// ForcesConfig represents physics simulation configuration.
|
|
|
|
type ForcesConfig struct {
|
|
|
|
layout.Config
|
|
|
|
Steps int
|
|
|
|
}
|
|
|
|
|
2018-09-19 12:45:54 +03:00
|
|
|
// NewForceEditor creates a new ForceEditor widget.
|
2018-10-19 22:10:56 +02:00
|
|
|
func NewForceEditor(apply func()) *ForceEditor {
|
2018-10-20 19:39:28 +02:00
|
|
|
f := &ForceEditor{}
|
|
|
|
f.config = DefaultForcesConfig
|
|
|
|
f.repelling = NewForceInput("Gravity:", f.config.Repelling)
|
|
|
|
f.spring = NewForceInput("Spring:", f.config.SpringStiffness)
|
|
|
|
f.drag = NewForceInput("Drag:", f.config.DragCoeff)
|
|
|
|
f.steps = NewRange("Steps:", f.config.Steps)
|
2018-10-20 19:42:05 +02:00
|
|
|
f.collapsable = NewCollapsable("Layout forces:", false,
|
2018-10-20 19:39:28 +02:00
|
|
|
f.applyButton,
|
|
|
|
f.repelling,
|
|
|
|
f.spring,
|
|
|
|
f.drag,
|
|
|
|
f.steps,
|
|
|
|
)
|
|
|
|
f.apply = apply
|
|
|
|
return f
|
2018-09-06 16:54:35 +03:00
|
|
|
}
|
|
|
|
|
2018-10-19 22:10:56 +02:00
|
|
|
// Render implements vecty's Component interface for ForceEditor.
|
|
|
|
func (f *ForceEditor) Render() vecty.ComponentOrHTML {
|
2018-10-20 14:47:19 +02:00
|
|
|
return Widget(
|
2018-10-20 19:39:28 +02:00
|
|
|
f.collapsable,
|
2018-10-19 22:10:56 +02:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2018-09-17 22:11:04 +03:00
|
|
|
// Config returns current forces & simulation configuration, getting values from UI.
|
2018-10-19 22:10:56 +02:00
|
|
|
func (f *ForceEditor) Config() ForcesConfig {
|
2018-09-17 22:11:04 +03:00
|
|
|
return ForcesConfig{
|
2018-10-19 22:10:56 +02:00
|
|
|
Steps: f.steps.Value(),
|
2018-09-17 22:11:04 +03:00
|
|
|
Config: layout.Config{
|
2018-10-19 22:10:56 +02:00
|
|
|
Repelling: f.repelling.Value(),
|
|
|
|
SpringStiffness: f.spring.Value(),
|
|
|
|
SpringLen: f.config.SpringLen,
|
|
|
|
DragCoeff: f.drag.Value(),
|
2018-09-17 22:11:04 +03:00
|
|
|
},
|
2018-09-06 20:07:24 +03:00
|
|
|
}
|
2018-09-06 16:54:35 +03:00
|
|
|
}
|
2018-10-19 22:10:56 +02:00
|
|
|
|
2018-10-20 19:39:28 +02:00
|
|
|
func (f *ForceEditor) applyButton() vecty.ComponentOrHTML {
|
|
|
|
return elem.Button(
|
|
|
|
vecty.Markup(
|
|
|
|
vecty.Class("button", "is-info", "is-small"),
|
|
|
|
event.Click(f.onClick),
|
2018-10-19 22:10:56 +02:00
|
|
|
),
|
2018-10-20 19:39:28 +02:00
|
|
|
vecty.Text("Apply"),
|
2018-10-19 22:10:56 +02:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *ForceEditor) onClick(e *vecty.Event) {
|
|
|
|
go f.apply()
|
|
|
|
}
|