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-23 13:29:38 +02:00
Steps : 100 ,
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
2018-10-23 13:29:38 +02:00
springLen * ForceInput
2018-10-20 19:39:28 +02:00
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
2018-10-23 15:10:13 +02:00
f . repelling = NewForceInput ( "Gravity:" , RepellingForceDescription , f . config . Repelling )
f . spring = NewForceInput ( "Spring:" , SpringForceDescription , f . config . SpringStiffness )
f . springLen = NewForceInput ( "Length:" , SpringLengthDescription , f . config . SpringLen )
f . drag = NewForceInput ( "Drag:" , DragForceDescritption , f . config . DragCoeff )
2018-10-27 09:45:12 +02:00
f . steps = NewRange ( "Steps:" , StepsDescription , f . config . Steps , 1 , 1000 , nil )
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 ,
2018-10-23 13:29:38 +02:00
f . springLen ,
2018-10-20 19:39:28 +02:00
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 ( ) ,
2018-10-23 13:29:38 +02:00
SpringLen : f . springLen . Value ( ) ,
2018-10-19 22:10:56 +02:00
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 ( )
}
2018-10-23 15:10:13 +02:00
const (
RepellingForceDescription = "Repelling force coefficient defines the force for nodes to repel from each other. It's a coefficent for Coulomb's law, and should be negative (positive is attraction)"
SpringForceDescription = "Spring force coefficient defines the force of attraction between linked nodes. It obeys Hooke's law. The larger the coefficient, the more stiffer the spring."
SpringLengthDescription = "Spring length defines a \"normal\" length of the spring. If link is shorted then this value, nodes start to repel, attract otherwise."
DragForceDescritption = "Drag force coefficient defines a drag force, that slows down nodes velocities after applying repelling and spring forces. Increase it if you see jitterness or too much movement on each iteration."
StepsDescription = "Number of physics simulation steps to run. Too big value may slowdown calculation without giving more benefit to the layout. Too little may not be enough to fully apply forces."
)