wardleyToGo

package module
v0.6.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 23, 2022 License: MIT Imports: 12 Imported by: 0

README

WardleyToGo

Go Reference Go codecov

A set of primitives to "code a map". In the context of the package "a map" represents a landscape. The landscape is made of "Components". Each component knows its own location on a map. Components can collaborate, meaning that they may be linked together. Therefore a map is also a graph. The entrypoint of this API is the 'Map' structure

Demo (deprecated)

Check the online demo at https://owulveryck.github.io/wardleyToGo/

Example

First, create a component type

type dummyComponent struct {
	id       int64
	position image.Point
}

func (d *dummyComponent) GetPosition() image.Point { return d.position }

func (d *dummyComponent) String() string { return strconv.FormatInt(d.id, 10) }

func (d *dummyComponent) ID() int64 { return d.id }

Then a collaboration structure (an edge)

type dummyCollaboration struct{ simple.Edge }

func (d *dummyCollaboration) GetType() wardleyToGo.EdgeType { return 0 }

func (d *dummyCollaboration) Draw(dst draw.Image, r image.Rectangle, src image.Image, sp image.Point) {
	coordsF := utils.CalcCoords(d.F.(wardleyToGo.Component).GetPosition(), r)
	coordsT := utils.CalcCoords(d.T.(wardleyToGo.Component).GetPosition(), r)
	drawing.Line(dst, coordsF.X, coordsF.Y, coordsT.X, coordsT.Y, color.Gray{Y: 128}, [2]int{})
}

And finally create the map

	m := wardleyToGo.NewMap(0)
	c0 := &dummyComponent{id: 0, position: image.Pt(25, 25)}
	c1 := &dummyComponent{id: 1, position: image.Pt(50, 50)}
	c2 := &dummyComponent{id: 2, position: image.Pt(50, 75)}
	c3 := &dummyComponent{id: 3, position: image.Pt(75, 75)}
	m.AddComponent(c0)
	m.AddComponent(c1)
	m.AddComponent(c2)
	m.AddComponent(c3)
	// c0 -> c1
	// c1 -> c2
	// c2 -> c3
	// c1 -> c3
	m.SetCollaboration(newCollaboration(c0, c1))
	m.SetCollaboration(newCollaboration(c1, c2))
	m.SetCollaboration(newCollaboration(c2, c3))
	m.SetCollaboration(newCollaboration(c1, c3))

Parser example

Create a map from the owm example (see https://onlinewardleymaps.com/#h4hJOoRdO4hHSljIb9 to build one):

title Tea Shop
anchor Business [0.95, 0.63]
anchor Public [0.95, 0.78]
component Cup of Tea [0.79, 0.61] label [19, -4]
component Cup [0.73, 0.78] label [19,-4] (dataProduct)
component Tea [0.63, 0.81]
component Hot Water [0.52, 0.80]
component Water [0.38, 0.82]
component Kettle [0.43, 0.35] label [-73, 4] (build)
evolve Kettle 0.62 label [22, 9] (buy)
component Power [0.1, 0.7] label [-29, 30] (outsource)
evolve Power 0.89 label [-12, 21]
Business->Cup of Tea
Public->Cup of Tea
Cup of Tea-collaboration>Cup
Cup of Tea-collaboration>Tea
Cup of Tea-collaboration>Hot Water
Hot Water->Water
Hot Water-facilitating>Kettle 
Kettle-xAsAService>Power
build Kettle


annotation 1 [[0.43,0.49],[0.08,0.79]] Standardising power allows Kettles to evolve faster
annotation 2 [0.48, 0.85] Hot water is obvious and well known
annotations [0.60, 0.02]

note +a generic note appeared [0.16, 0.36]

style wardley
streamAlignedTeam stream aligned A [0.84, 0.18, 0.76, 0.95]
enablingTeam team B [0.9, 0.30, 0.30, 0.40]
platformTeam team C [0.18, 0.61, 0.02, 0.94]
complicatedSubsystemTeam team D [0.92, 0.73, 0.45, 0.90]
package main

import (
	"fmt"
	"log"
	"os"

	"github.com/owulveryck/wardleyToGo/parser/owm"
)

func main() {
	p := owm.NewParser(os.Stdin)
	m, err := p.Parse() // the map
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(m)
}
> cat examples/parser/sample.owm | go run examples/parser/main.go
2021/04/12 10:03:12 Warning unhandled element at line 21: build Kettle
2021/04/12 10:03:12 Warning unhandled element at line 28: note a generic note appeared
2021/04/12 10:03:12 Warning unhandled element at line 30: style wardley
map {
        0 'Business' [95,63];
        8 '[evolved]Kettle' [43,35];
        1 'Public' [95,78];
        3 'Cup' [73,78];
        9 'Power' [10,70];
        10 '[evolved]Power' [10,70];
        11 'stream aligned A' [76,18,84,95];
        14 'team D' [45,73,92,90];
        5 'Hot Water' [52,80];
        7 'Kettle' [43,35];
        12 'team B' [30,30,90,40];
        2 'Cup of Tea' [79,61];
        4 'Tea' [63,81];
        6 'Water' [38,82];
        13 'team C' [2,61,18,94];

        5 -> 6 [0];
        5 -> 7 [129];
        5 -> 8 [66];
        7 -> 8 [65];
        7 -> 9 [130];
        7 -> 10 [66];
        2 -> 3 [128];
        2 -> 4 [128];
        2 -> 5 [128];
        0 -> 2 [0];
        8 -> 9 [66];
        8 -> 10 [66];
        1 -> 2 [0];
        9 -> 10 [65];
}

Full sample

This example instanciates a parser, reads a modified version of the online wardleymap and renders it as an SVG:

title Tea Shop
anchor Business [0.95, 0.63]
anchor Public [0.95, 0.78]
component Cup of Tea [0.79, 0.61] label [19, -4]
component Cup [0.73, 0.78] label [19,-4] (dataProduct)
component Tea [0.63, 0.81]
component Hot Water [0.52, 0.80]
component Water [0.38, 0.82]
component Kettle [0.43, 0.35] label [-73, 4] (build)
evolve Kettle 0.62 label [22, 9] (buy)
component Power [0.1, 0.7] label [-29, 30] (outsource)
evolve Power 0.89 label [-12, 21]
Business->Cup of Tea
Public->Cup of Tea
Cup of Tea-collaboration>Cup
Cup of Tea-collaboration>Tea
Cup of Tea-collaboration>Hot Water
Hot Water->Water
Hot Water-facilitating>Kettle 
Kettle-xAsAService>Power
build Kettle


annotation 1 [[0.43,0.49],[0.08,0.79]] Standardising power allows Kettles to evolve faster
annotation 2 [0.48, 0.85] Hot water is obvious and well known
annotations [0.60, 0.02]

note +a generic note appeared [0.16, 0.36]

style wardley
streamAlignedTeam stream aligned A [0.84, 0.18, 0.76, 0.95]
enablingTeam team B [0.9, 0.30, 0.30, 0.40]
platformTeam team C [0.18, 0.61, 0.02, 0.94]
complicatedSubsystemTeam team D [0.92, 0.73, 0.45, 0.90]
package main

import (
	"image"
	"log"
	"os"

	svgmap "github.com/owulveryck/wardleyToGo/encoding/svg"
	"github.com/owulveryck/wardleyToGo/parser/owm"
)

func main() {
	p := owm.NewParser(os.Stdin)
	m, err := p.Parse() // the map
	if err != nil {
		log.Fatal(err)
	}
	e, err := svgmap.NewEncoder(os.Stdout, image.Rect(0, 0, 1100, 900), image.Rect(30, 50, 1070, 850))
	if err != nil {
		log.Fatal(err)
	}
	defer e.Close()
	style := svgmap.NewWardleyStyle(svgmap.DefaultEvolution)
	e.Init(style)
	err = e.Encode(m)
	if err != nil {
		log.Fatal(err)
	}
}

output

Generating image, png and so on.. (WIP)

the map fulfills the drawer.Drawer interface. If the components fulfills the interface as well, they are displayend on an image.

func main() {
	p := owm.NewParser(os.Stdin)
	m, err := p.Parse() // the map
	if err != nil {
		log.Fatal(err)
	}
	im := image.NewRGBA(image.Rect(0, 0, 1400, 1100))
	canvas := image.Rect(100, 100, 1300, 1000)
	createBackground(im, canvas)

	m.Draw(im, canvas, im, image.Point{})
	png.Encode(os.Stdout, im)
}

see the examples/pngoutput directory

png output

Documentation

Overview

Package wardleyToGo provides primitives to build an in-memory map (a plan).

In the context of the package "a map" represents a landscape.

The landscape is made of "Components". Each component knows its own location on a map.

Components can collaborate, meaning that they may be linked together. Therefore a map is also a graph.

The entrypoint of this API is the 'Map' structure

Example (Canvas)
package main

import (
	"fmt"
	"image"
	"image/color"
	"image/draw"
	"math"
	"strconv"

	"github.com/owulveryck/wardleyToGo"
	"github.com/owulveryck/wardleyToGo/internal/drawing"
	"github.com/owulveryck/wardleyToGo/internal/utils"
	"gonum.org/v1/gonum/graph"
	"gonum.org/v1/gonum/graph/path"
	"gonum.org/v1/gonum/graph/simple"
)

type dummyComponent struct {
	id       int64
	position image.Point
}

func (d *dummyComponent) GetPosition() image.Point { return d.position }

func (d *dummyComponent) String() string { return strconv.FormatInt(d.id, 10) }

func (d *dummyComponent) ID() int64 { return d.id }

func (d *dummyComponent) Draw(dst draw.Image, r image.Rectangle, src image.Image, sp image.Point) {
	coords := utils.CalcCoords(d.position, r)
	dst.Set(coords.X, coords.Y, color.Gray{Y: 255})
}

type dummyCollaboration struct{ simple.Edge }

func (d *dummyCollaboration) GetType() wardleyToGo.EdgeType { return 0 }

func (d *dummyCollaboration) Draw(dst draw.Image, r image.Rectangle, src image.Image, sp image.Point) {
	coordsF := utils.CalcCoords(d.F.(wardleyToGo.Component).GetPosition(), r)
	coordsT := utils.CalcCoords(d.T.(wardleyToGo.Component).GetPosition(), r)
	drawing.Line(dst, coordsF.X, coordsF.Y, coordsT.X, coordsT.Y, color.Gray{Y: 128}, [2]int{})
}

func newCollaboration(a, b wardleyToGo.Component) wardleyToGo.Collaboration {
	return &dummyCollaboration{Edge: simple.Edge{F: a, T: b}}
}

func main() {
	// Create a new map
	m := wardleyToGo.NewMap(0)
	c0 := &dummyComponent{id: 0, position: image.Pt(25, 25)}
	c1 := &dummyComponent{id: 1, position: image.Pt(50, 50)}
	c2 := &dummyComponent{id: 2, position: image.Pt(50, 75)}
	c3 := &dummyComponent{id: 3, position: image.Pt(75, 75)}
	m.AddComponent(c0)
	m.AddComponent(c1)
	m.AddComponent(c2)
	m.AddComponent(c3)
	// c0 -> c1
	// c1 -> c2
	// c2 -> c3
	// c1 -> c3
	m.SetCollaboration(newCollaboration(c0, c1))
	m.SetCollaboration(newCollaboration(c1, c2))
	m.SetCollaboration(newCollaboration(c2, c3))
	m.SetCollaboration(newCollaboration(c1, c3))

	// Creates a picture representation of the map
	const width = 80
	const height = 40

	im := image.NewGray(image.Rectangle{Max: image.Point{X: width, Y: height}})
	m.Canvas = &simpleCanvas{}

	m.Draw(im, image.Rect(5, 2, 75, 38), im, image.Point{X: 0, Y: 0})
	//m.Draw(im, im.Bounds(), im, image.Point{X: 0, Y: 0})
	// Very trivial example to draw a map on stdout
	render(im)

	//	drawMap(m)

	// Find the shortest path betwen c0 and c3
	p, _ := path.AStar(c0, c3, m, euclideanDistance)
	c0Toc3, _ := p.To(c3.ID())
	fmt.Printf("Shortest path from c0 to c3: ")
	for _, c := range c0Toc3 {
		fmt.Printf("-%v", c.ID())
	}
}

type simpleCanvas struct{}

func (s *simpleCanvas) Draw(dst draw.Image, r image.Rectangle, src image.Image, sp image.Point) {
	draw.Draw(dst, r, image.NewUniform(color.Gray{Y: 64}), sp, draw.Src)
}

func render(im image.Image) {
	width := im.Bounds().Dx()
	pi := image.NewPaletted(im.Bounds(), []color.Color{
		color.Gray{Y: 255},
		color.Gray{Y: 160},
		color.Gray{Y: 70},
		color.Gray{Y: 35},
		color.Gray{Y: 0},
	})

	draw.FloydSteinberg.Draw(pi, im.Bounds(), im, image.Point{})
	shade := []string{" ", "░", "▒", "▓", "█"}
	for i, p := range pi.Pix {
		fmt.Print(shade[p])
		if (i+1)%width == 0 {
			fmt.Print("\n")
		}
	}
}

var euclideanDistance path.Heuristic = func(x, y graph.Node) float64 {
	xC := x.(wardleyToGo.Component).GetPosition()
	yC := y.(wardleyToGo.Component).GetPosition()
	a := xC.X - yC.X
	b := xC.Y - yC.Y
	return math.Sqrt(float64(a*a) + float64(b*b))
}
Output:

████████████████████████████████████████████████████████████████████████████████
████████████████████████████████████████████████████████████████████████████████
█████▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒█████
█████▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒█████
█████▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒█████
█████▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒█████
█████▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒█████
█████▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒█████
█████▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒█████
█████▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒█████
█████▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒█████
█████▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓ ░▓▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▒█████
█████▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒█████
█████▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▒▒▒▒░░▓▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▒▒▒█████
█████▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒▓▒▒▓▒░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▒█████
█████▒▓▒▒▓▒▒▓▒▒▓▒▓▒▒▒▒▒▒▒▒▒▓▒▒░░▓▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▒▒▒▓▒█████
█████▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▓▒▒▓▒▒▒▒▓▒░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▒▒▒█████
█████▒▒▓▒▒▓▒▒▓▒▒▓▒▒▒▒▒▒▒▒▒▒▒▓▒▒▓▒▒░░▓▒▓▒▒▓▒▒▓▒▓▒▓▒▓▒▒▓▒▓▒▓▒▓▒▒▓▒▓▒▓▒▒▒▒▓▒▒▓█████
█████▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▓▒▒▓▒▒▒▒▒▒▒▒▓▓░░▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▒▒▒█████
█████▒▓▒▒▓▒▒▓▒▓▒▒▓▒▒▒▒▒▒▒▒▒▒▓▒▒▓▒▒▒▒▓▒░▒▒▒▓▒▒▓▒▒▒▒▒▓▒▒▒▓▒▒▒▒▓▒▒▒▓▒▒▓▒▒▒▒▓▒▒█████
█████▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▓▒▒▓▒▒▒▒▒▒▒▓▒▒▓▒▒ ▒▒▒▒▒▒▒▓▒▒▒▒▓▒▒▒▒▓▒▒▒▓▒▒▒▒▒▒▒▒▒▒▒▒█████
█████▒▒▓▒▒▓▒▒▒▓▒▒▒▓▒▒▒▒▒▒▒▒▒▒▒▓▒▒▒▒▒▒▒▒▒░▒░▓▒▒▓▒▒▒▓▒▒▒▒▒▓▒▒▒▒▒▒▒▒▒▓▒▒▓▒▒▓▒▒█████
█████▒▒▒▒▒▒▒▓▒▒▒▓▒▒▒▒▒▓▒▒▓▒▒▓▒▒▒▓▒▒▒▓▒▒▓░▒▒░▒▒▒▒▒▒▒▒▒▓▒▒▒▒▒▒▓▒▒▓▒▒▒▒▒▒▒▒▒▒▒█████
█████▒▓▒▒▓▒▒▒▒▒▒▒▒▒▒▓▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▒▒▒▒▒▒▓▒░░▓▒▒▓▒▒▒▒▒▒▓▒▒▒▒▒▒▒▒▓▒▒▓▒▒▓▒▒█████
█████▒▒▒▒▒▒▒▓▒▒▓▒▒▓▒▒▒▒▓▒▒▓▒▒▓▒▒▓▒▒▒▒▒▓▒░▒▒▒▒▓▒░▒▒▒▒▒▓▒▒▒▒▒▓▒▒▓▒▒▒▒▒▒▒▒▒▒▒▓█████
█████▒▒▓▒▒▓▒▒▒▒▒▒▒▒▒▒▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▒░▓▒▒▒▒▓▒▒░▒▒▒▒▒▓▒▒▒▒▒▒▒▒▓▒▒▓▒▒▓▒▒▒▒█████
█████▒▒▒▒▒▒▒▒▓▒▒▓▒▒▓▒▒▒▒▒▓▒▒▓▒▒▓▒▒▓▒▒▒▒▓░▓▒▓▒▒▒▒▒▒▒░▒▒▒▒▒▓▒▒▓▒▒▒▒▒▒▒▒▒▒▒▓▒▒█████
█████▒▒▓▒▒▓▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓░▓▒▒▒▒▓▒▒▓▒▒▒░░▓▒▒▒▒▒▒▓▒▒▓▒▒▓▒▒▒▒▒▒█████
█████▒▒▒▒▒▒▒▒▓▒▒▓▒▒▒▓▒▒▒▒▒▓▒▒▓▒▒▓▒▒▓▒▓▒▒░▓▒▒▒▒▒▒▒▒▒▒▒▓▓░▒▒▒▒▓▒▒▒▒▒▒▒▒▒▓▒▒▓▒█████
█████▒▓▒▒▓▒▒▒▒▒▒▒▒▓▒▒▒▒▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓ ░▒░▒░▒░▒░▒░▒░░▒░ ▒▒▒▒▒▓▒▒▓▒▒▒▒▒▒▒▒█████
█████▒▒▒▒▒▒▓▒▒▓▒▒▒▒▒▒▓▒▒▒▒▓▒▒▓▒▒▓▒▒▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▒▒▒▒▒▒▓▒▒▓▒▒▒█████
█████▒▒▓▒▒▒▒▒▒▒▒▓▒▒▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▓▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▒▒▒▒▓▒▒▓▒▒▒▒▒▒▒▒▓▒█████
█████▒▒▒▒▓▒▒▓▒▒▒▒▒▒▒▒▒▒▓▒▓▒▒▓▒▒▓▒▒▓▒▒▒▒▒▒▒▒▒▓▒▒▓▒▒▓▒▒▒▒▒▒▓▒▒▒▒▒▒▒▒▓▒▒▓▒▒▒▒▒█████
█████▒▓▒▒▒▒▒▒▒▓▒▒▓▒▒▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▓▒▒▓▒▒▒▒▒▒▒▒▒▓▒▒▓▒▒▒▓▒▒▓▒▒▒▒▒▒▒▒▓▒▒▓█████
█████▒▒▒▒▓▒▒▓▒▒▒▒▒▒▒▒▒▒▓▒▒▓▒▒▓▒▒▓▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▓▒▒▒▒▒▒▒█████
█████▒▒▓▒▒▒▒▒▒▒▓▒▒▓▒▒▓▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▓▒▒▓▒▒▓▒▒▒▒▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▒▒▒▒▓▒▓▒▒▒█████
█████▒▒▒▒▒▓▒▒▓▒▒▒▒▒▒▒▒▒▒▓▒▒▓▒▒▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▒▒▒▒▒▓▒█████
█████▒▒▓▒▒▒▒▒▒▒▒▓▒▒▓▒▒▓▒▒▒▒▒▒▒▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▒▒▓▒▒▓▒▒▓▒▒▓▒▒▓▒▒▒▒▒▓▒▒▓▒▒▒▒█████
████████████████████████████████████████████████████████████████████████████████
████████████████████████████████████████████████████████████████████████████████
Shortest path from c0 to c3: -0-1-3

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Annotation

type Annotation struct {
	Identifier int
	Placements []image.Point
	Label      string
}

An annotation is a set of placements of a certain label

func NewAnnotation

func NewAnnotation(identifier int) *Annotation

func (*Annotation) MarshalSVG added in v0.3.3

func (a *Annotation) MarshalSVG(e *xml.Encoder, canvas image.Rectangle) error

func (*Annotation) String

func (a *Annotation) String() string

type Area

type Area interface {
	// GetArea should be expressed wrt a 100x100 map
	GetArea() image.Rectangle
	graph.Node
}

An area is anything that covers a rectangle area on a map

type Collaboration

type Collaboration interface {
	graph.Edge
	GetType() EdgeType
}

A Collaboration is an edge between two components with a certain type

type Component

type Component interface {
	// GetPosition of the element wrt a 100x100 map
	GetPosition() image.Point
	graph.Node
}

A Component is a node of a graph that have coordinates. A Component can represent iself on a 100x100 map

type ComponentType

type ComponentType uint8

a ComponentType

type EdgeType

type EdgeType uint8

The EdgeType

type Map

type Map struct {
	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

	*simple.DirectedGraph
	// contains filtered or unexported fields
}

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)}

func NewMap

func NewMap(id int64) *Map

NewMap with initial area of 100x100

func (*Map) AddComponent

func (m *Map) AddComponent(e Component) error

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 (*Map) Draw

func (m *Map) Draw(dst draw.Image, r image.Rectangle, src image.Image, sp image.Point)

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 (*Map) GetArea

func (m *Map) GetArea() image.Rectangle

func (*Map) GetPosition

func (m *Map) GetPosition() image.Point

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 (*Map) ID

func (m *Map) ID() int64

a Map fulfills the graph.Node interface; thererfore if can be part of a graph of maps

func (*Map) SetCollaboration

func (m *Map) SetCollaboration(e Collaboration) error

func (*Map) String

func (m *Map) String() string
Example
package main

import (
	"fmt"
	"image"
	"image/color"
	"image/draw"
	"strconv"

	"github.com/owulveryck/wardleyToGo"
	"github.com/owulveryck/wardleyToGo/internal/drawing"
	"github.com/owulveryck/wardleyToGo/internal/utils"
	"gonum.org/v1/gonum/graph/simple"
)

type dummyComponent struct {
	id       int64
	position image.Point
}

func (d *dummyComponent) GetPosition() image.Point { return d.position }

func (d *dummyComponent) String() string { return strconv.FormatInt(d.id, 10) }

func (d *dummyComponent) ID() int64 { return d.id }

func (d *dummyComponent) Draw(dst draw.Image, r image.Rectangle, src image.Image, sp image.Point) {
	coords := utils.CalcCoords(d.position, r)
	dst.Set(coords.X, coords.Y, color.Gray{Y: 255})
}

type dummyCollaboration struct{ simple.Edge }

func (d *dummyCollaboration) GetType() wardleyToGo.EdgeType { return 0 }

func (d *dummyCollaboration) Draw(dst draw.Image, r image.Rectangle, src image.Image, sp image.Point) {
	coordsF := utils.CalcCoords(d.F.(wardleyToGo.Component).GetPosition(), r)
	coordsT := utils.CalcCoords(d.T.(wardleyToGo.Component).GetPosition(), r)
	drawing.Line(dst, coordsF.X, coordsF.Y, coordsT.X, coordsT.Y, color.Gray{Y: 128}, [2]int{})
}

func newCollaboration(a, b wardleyToGo.Component) wardleyToGo.Collaboration {
	return &dummyCollaboration{Edge: simple.Edge{F: a, T: b}}
}

func main() {
	// Create a new map
	m := wardleyToGo.NewMap(0)
	c0 := &dummyComponent{id: 0, position: image.Pt(25, 25)}
	c1 := &dummyComponent{id: 1, position: image.Pt(50, 50)}
	c2 := &dummyComponent{id: 2, position: image.Pt(50, 75)}
	c3 := &dummyComponent{id: 3, position: image.Pt(75, 75)}
	m.AddComponent(c0)
	m.AddComponent(c1)
	m.AddComponent(c2)
	m.AddComponent(c3)
	// c0 -> c1
	// c1 -> c2
	// c2 -> c3
	// c1 -> c3
	m.SetCollaboration(newCollaboration(c0, c1))
	m.SetCollaboration(newCollaboration(c1, c2))
	m.SetCollaboration(newCollaboration(c2, c3))
	m.SetCollaboration(newCollaboration(c1, c3))
	fmt.Println(m)
}
Output:

Directories

Path Synopsis
dot
svg
examples
internal
svg
parser
owm
wtg

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL