package routes import ( "embed" "html/template" "log" "math" "net/http" "slices" "sunshine.industries/some-automoderation/rooms" ) type brickState struct { TemplateType string Gesture rooms.HandGesture } type personData struct { Name string IsSpeaker bool IsMark bool IsRaised bool Raised rooms.HandGesture Mark rooms.HandGesture Index int } // data to be passed to "roomPeople" template type roomTableData struct { *rooms.Room currentPerson rooms.PersonId } func (room *roomTableData) Persons() []personData { total := room.Total() persons := make([]personData, 0, total) currentPersonIndex := slices.Index(room.Paricipants, room.currentPerson) for i, pId := range room.Paricipants { personData := personDataFromRoom(room, pId) // to have index 0 for 'current person' personData.Index = (i - currentPersonIndex + total) % total persons = append(persons, personData) } return persons } func (r *roomTableData) Total() int { return len(r.Paricipants) } func (r *roomTableData) Tangens() float64 { total := r.Total() if total == 2 { return 1 } if total == 1 { return 500 } return math.Tan(math.Pi / float64(r.Total())) // Math.tan(Math.PI/m); } type arrowData struct { IsVisible bool Height, Width int Radius int StartX, StartY int EndX, EndY int LargeArcFlag int Angle1X, Angle1Y int Angle2X, Angle2Y int } // arrow data - to draw SVG from current speaker to next speaker func (r *roomTableData) ArrowData() arrowData { // TODO figure out size to be around the people // and this is somewhat a win height, width := 150.0, 150.0 centerX, centerY := height/2, width/2 total := r.Total() // speakerIndex := slices.Index(r.Paricipants, r.CurrentSpeaker) currentPersonIndex := slices.Index(r.Paricipants, r.currentPerson) nextSpeakerIndex, found, countedFromIndex := r.NextSpeakerIndex() if !found { return arrowData{} } startSector := countedFromIndex + total - currentPersonIndex endSector := nextSpeakerIndex + total - currentPersonIndex if endSector < startSector { endSector += total } radius := 50.0 startAngle := 90 + float64(startSector)*(360.0/float64(total)) endAngle := 90 + float64(endSector)*(360.0/float64(total)) // if need to draw full circle if startSector == endSector { startAngle += 3 // a bit forward endAngle += 357 // ~ a bit backward (almost full circle forward) } startAngleRad := startAngle * (math.Pi / float64(180)) endAngleRad := endAngle * (math.Pi / float64(180)) // endAngle is radius angle, so perpendicular gives direction of teh arrow x1 := centerX + radius*math.Cos(startAngleRad) y1 := centerY + radius*math.Sin(startAngleRad) x2 := centerX + radius*math.Cos(endAngleRad) y2 := centerY + radius*math.Sin(endAngleRad) arrowAngleOffset := math.Pi / 4 // 45 degrees arrowPointDirection := endAngleRad - math.Pi/2 arrowheadLen := 10.0 arrowMinusAngle := arrowPointDirection - arrowAngleOffset arrowPlusAngle := arrowPointDirection + arrowAngleOffset arrowMinusEndX := x2 + arrowheadLen*math.Cos(arrowMinusAngle) arrowMinusEndY := y2 + arrowheadLen*math.Sin(arrowMinusAngle) arrowPlusEndX := x2 + arrowheadLen*math.Cos(arrowPlusAngle) arrowPlusEndY := y2 + arrowheadLen*math.Sin(arrowPlusAngle) // indicates that the shorter of the two possible arcs should be used. largeArcFlag := 0 // if endAngleRad-startAngleRad > (math.Pi) { // specifies that the longer arc should be chosen. largeArcFlag = 1 } return arrowData{ IsVisible: true, Height: int(height), Width: int(width), Radius: int(radius), StartX: int(x1), StartY: int(y1), EndX: int(x2), EndY: int(y2), LargeArcFlag: largeArcFlag, Angle1X: int(arrowMinusEndX), Angle1Y: int(arrowMinusEndY), Angle2X: int(arrowPlusEndX), Angle2Y: int(arrowPlusEndY), } } func personDataFromRoom(room *roomTableData, pId rooms.PersonId) personData { person, exists := room.AllKnownPeople[pId] if !exists || !slices.Contains(room.Paricipants, pId) { return personData{} } hand, handExists := room.ParticipantHands[pId] var mark rooms.HandGesture var markExists bool for gesture := rooms.ChangeTopic; gesture <= rooms.Meta; gesture++ { if room.Marks[gesture] == pId { markExists = true mark = gesture } } isSpeaker := room.CurrentSpeaker == pId return personData{ Name: person.Name, IsSpeaker: isSpeaker, IsRaised: handExists, Raised: hand, IsMark: markExists, Mark: mark, } } func (pData personData) BricksForPerson() []brickState { var result = make([]brickState, 5) for gesture := rooms.ChangeTopic; gesture <= rooms.Meta; gesture++ { // for index := rooms.Meta; index >= rooms.ChangeTopic; index-- { // log.Printf(">>>>> iteraging for %d", gesture) // this results in iteration 4,3,2,1,0,255 wow templateType := "inactiveBrick" switch { case pData.IsRaised && pData.IsMark && gesture == pData.Raised: templateType = "markAndRaisedBrick" case pData.IsMark && gesture == pData.Mark: templateType = "markBrick" case pData.IsSpeaker && gesture == pData.Raised: templateType = "speakerBrick" case pData.IsRaised && gesture == pData.Raised: templateType = "raisedBrick" } result[gesture] = brickState{ TemplateType: templateType, Gesture: gesture, } } slices.Reverse(result) return result } func roomTemplatesPreview( templateFs *embed.FS, ) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { testPersonData := personData{ Name: "John Doe", IsRaised: true, Raised: rooms.Expand, IsMark: true, Mark: rooms.ProbingQ, } var person1 = rooms.Person{ Id: rooms.PersonId(100), Name: "test person name 1", } var person2 = rooms.Person{ Id: rooms.PersonId(200), Name: "test person name 2", } var person3 = rooms.Person{ Id: rooms.PersonId(300), Name: "test person name 3", } var person4 = rooms.Person{ Id: rooms.PersonId(400), Name: "test person name 4", } aRoom := rooms.Room{ Name: "test", CurrentSpeaker: person3.Id, AllKnownPeople: map[rooms.PersonId]rooms.Person{ person1.Id: person1, person2.Id: person2, person3.Id: person3, person4.Id: person4, }, Paricipants: []rooms.PersonId{ person1.Id, person2.Id, person3.Id, person4.Id, }, ParticipantHands: map[rooms.PersonId]rooms.HandGesture{ person3.Id: rooms.ClarifyingQ, person2.Id: rooms.Meta, person4.Id: rooms.ChangeTopic, }, Marks: map[rooms.HandGesture]rooms.PersonId{ rooms.Expand: person1.Id, rooms.ChangeTopic: person4.Id, }, } contentData := struct { DefaultColor template.CSS GesturePreviews []rooms.HandGesture ABrick brickState TestPerson personData ARoom *roomTableData }{ DefaultColor: "--expand-color", ABrick: brickState{ TemplateType: "raisedBrick", Gesture: rooms.Expand, }, GesturePreviews: rooms.GesturesHighToLow[:], TestPerson: testPersonData, ARoom: &roomTableData{ Room: &aRoom, currentPerson: aRoom.Paricipants[0], }, } pageData := pageData{ Header: headerData{Title: "look at the room templates"}, Content: contentData, } baseFile := "templates/base.gohtml" tmpl := template.Must(template.New("").ParseFS(templateFs, baseFile, "templates/tableTemplates.gohtml", "templates/tableTemplatesPreview.gohtml", )) err := tmpl.ExecuteTemplate(w, "full-page", pageData) if err != nil { log.Printf("yoyo, error %s", err) } } }