-
-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathmap.go
135 lines (122 loc) · 3.69 KB
/
map.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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package wardleyToGo
import (
"errors"
"fmt"
"image"
"image/draw"
"strings"
"gonum.org/v1/gonum/graph/simple"
)
// a Map is a directed graph whose components knows their own position wrt to an anchor.
// The anchor is the point A of a rectangle as defined by
//
// A := image.Point{}
// image.Rectangle{A, Pt(100, 100)}
type Map struct {
id int64
Title string
// Canvas is the function that will draw the initial map
// allowing the placement of the axis, legend and so on
Canvas draw.Drawer
Annotations []*Annotation
AnnotationsPlacement image.Point
area image.Rectangle
*simple.DirectedGraph
}
func (m *Map) String() string {
var b strings.Builder
b.WriteString("map {\n")
nodes := m.DirectedGraph.Nodes()
for nodes.Next() {
n := nodes.Node().(Component)
if a, ok := n.(Area); ok {
b.WriteString(
fmt.Sprintf("\t%v '%v' [%v,%v,%v,%v];\n", a.ID(), a,
a.GetArea().Min.X, a.GetArea().Min.Y,
a.GetArea().Max.X, a.GetArea().Max.Y))
} else {
b.WriteString(fmt.Sprintf("\t%v '%v' [%v,%v];\n", n.ID(), n, n.GetPosition().X, n.GetPosition().Y))
}
}
b.WriteString("\n")
edges := m.DirectedGraph.Edges()
for edges.Next() {
e := edges.Edge().(Collaboration)
b.WriteString(fmt.Sprintf("\t%v -> %v [%v];\n", e.From().ID(), e.To().ID(), e.GetType()))
}
b.WriteString("}\n")
return b.String()
}
// NewMap with initial area of 100x100
func NewMap(id int64) *Map {
return &Map{
id: id,
area: image.Rect(0, 0, 100, 100),
DirectedGraph: simple.NewDirectedGraph(),
}
}
// a Map fulfills the graph.Node interface; thererfore if can be part of a graph of maps
func (m *Map) ID() int64 {
return m.id
}
// GetPosition fulfills the componnts.Component interface. Therefore a map can be a component of another map.
// This allows doing submaping.
// The position is the center of the area of the map
func (m *Map) GetPosition() image.Point {
return image.Pt((m.area.Max.X-m.area.Min.X)/2, (m.area.Max.Y-m.area.Min.Y)/2)
}
func (m *Map) GetArea() image.Rectangle {
return m.area
}
// Draw aligns r.Min in dst with sp in src and then replaces the
// rectangle r in dst with the result of drawing src on dst.
// If the Components and Collaboration elemts of the maps are draw.Drawer, their methods
// are called accordingly
func (m *Map) Draw(dst draw.Image, r image.Rectangle, src image.Image, sp image.Point) {
if m.Canvas != nil {
m.Canvas.Draw(dst, r, src, sp)
}
// Draw edges first
edges := m.Edges()
for edges.Next() {
if e, ok := edges.Edge().(draw.Drawer); ok {
e.Draw(dst, r, src, sp)
}
}
nodes := m.Nodes()
for nodes.Next() {
if n, ok := nodes.Node().(draw.Drawer); ok {
n.Draw(dst, r, src, sp)
}
}
}
// SVG representation, class is subMapElement and element
/*
func (m *Map) SVG(s *svg.SVG, bounds image.Rectangle) {
coords := utils.CalcCoords(m.GetPosition(), bounds)
s.Gid(strconv.FormatInt(m.id, 10))
s.Translate(coords.X, coords.Y)
s.Text(10, 10, m.Title)
s.Circle(0, 0, 5, `stroke-width="1"`, `stroke="black"`, `fill="black"`, `class="subMapElement, element"`)
s.Gend()
s.Gend()
}
*/
// AddComponent add e to the graph. It returns an error if e is out-of-bounds,
// meaning its coordinates are less than 0 or more that 100
func (m *Map) AddComponent(e Component) error {
if !e.GetPosition().In(image.Rect(0, 0, 100, 100)) {
return errors.New("component out of bounds")
}
m.DirectedGraph.AddNode(e)
return nil
}
func (m *Map) SetCollaboration(e Collaboration) error {
m.DirectedGraph.SetEdge(e)
return nil
}
// Chainer is a component that is part of a value chain
type Chainer interface {
// GetAbsoluteVisibility returns the visibility of the component as seen from the anchor
GetAbsoluteVisibility() int
}