-
Notifications
You must be signed in to change notification settings - Fork 5
/
wobble.go
89 lines (75 loc) · 1.78 KB
/
wobble.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
package main
import (
"math/rand"
"time"
"github.com/divan/graphx/layout"
)
const (
WobblingPeriod = 2 * time.Second
WobblingCoeff = 0.2 // the larger, the bigger distance of wobbling
)
// Wobbling implements wobbling effect for graph nodes.
//
// It updates positions and calls scene methods to update objects accordingly.
type Wobbling struct {
lastChange time.Time // timestamp of last direction change
forward bool
directions map[string]*Direction
positions map[string]*layout.Object
}
// NewWobbling creates a new wobbling effect for graph.
func NewWobbling(positions map[string]*layout.Object) *Wobbling {
return &Wobbling{
positions: positions,
directions: make(map[string]*Direction),
}
}
// Animate will run on every requestAnimationStep call.
func (w *Wobbling) Animate() {
if w == nil {
return
}
if time.Now().After(w.lastChange) {
w.changeDirection()
w.lastChange = time.Now().Add(WobblingPeriod)
}
w.wobbleNodes()
}
func (w *Wobbling) wobbleNodes() {
for id, pos := range w.positions {
d := w.directions[id]
pos.SetPosition(pos.X()+d.X, pos.Y()+d.Y, pos.Z()+d.Z)
}
}
func (w *Wobbling) changeDirection() {
rand.Seed(time.Now().UnixNano())
w.forward = !w.forward
for id := range w.positions {
var direction *Direction
if w.forward {
direction = NewRandomDirection()
} else {
// return to original position
orig := w.directions[id]
direction = orig.Reverse()
}
w.directions[id] = direction
}
}
type Direction struct {
X, Y, Z float64
}
func NewRandomDirection() *Direction {
return &Direction{
X: (rand.Float64() - 0.5) * WobblingCoeff,
Y: (rand.Float64() - 0.5) * WobblingCoeff,
Z: (rand.Float64() - 0.5) * WobblingCoeff,
}
}
func (d *Direction) Reverse() *Direction {
return &Direction{
X: -d.X,
Y: -d.Y,
Z: -d.Z,
}
}