diff --git a/doc/images/drei_tische_kette_paare.svg b/doc/images/drei_tische_kette_paare.svg
index 4b3a405..f04c31e 100644
--- a/doc/images/drei_tische_kette_paare.svg
+++ b/doc/images/drei_tische_kette_paare.svg
@@ -2,18 +2,21 @@
diff --git a/doc/images/sechs_tische_kreis_dreiergruppen.svg b/doc/images/sechs_tische_kreis_dreiergruppen.svg
index 2bd505b..fb1bbe0 100644
--- a/doc/images/sechs_tische_kreis_dreiergruppen.svg
+++ b/doc/images/sechs_tische_kreis_dreiergruppen.svg
@@ -6,33 +6,39 @@
-
-
-
-0
+Vorname10 Nachname10 — Gruppe 4
+Vorname7 Nachname7 — Gruppe 3
+
+0
+2 Pl.
-
-
-
-0
+Vorname11 Nachname11 — Gruppe 4
+Vorname12 Nachname12 — Gruppe 4
+
+0
+2 Pl.
-
-
-
-0
+Vorname2 Nachname2 — Gruppe 1
+Vorname3 Nachname3 — Gruppe 1
+
+0
+2 Pl.
-
-
-
-0
+Vorname1 Nachname1 — Gruppe 1
+Vorname4 Nachname4 — Gruppe 2
+
+0
+2 Pl.
-
-
-
-0
+Vorname5 Nachname5 — Gruppe 2
+Vorname6 Nachname6 — Gruppe 2
+
+0
+2 Pl.
-
-
-
-0
+Vorname8 Nachname8 — Gruppe 3
+Vorname9 Nachname9 — Gruppe 3
+
+0
+2 Pl.
diff --git a/doc/images/vier_tische_linie_viergruppen.svg b/doc/images/vier_tische_linie_viergruppen.svg
index 4b0600b..cb8f68a 100644
--- a/doc/images/vier_tische_linie_viergruppen.svg
+++ b/doc/images/vier_tische_linie_viergruppen.svg
@@ -4,23 +4,27 @@
-
-
-
-0
+Vorname8 Nachname8 — Gruppe 2
+Vorname5 Nachname5 — Gruppe 2
+
+0
+2 Pl.
-
-
-
-0
+Vorname6 Nachname6 — Gruppe 2
+Vorname7 Nachname7 — Gruppe 2
+
+0
+2 Pl.
-
-
-
-0
+Vorname3 Nachname3 — Gruppe 1
+Vorname4 Nachname4 — Gruppe 1
+
+0
+2 Pl.
-
-
-
-0
+Vorname1 Nachname1 — Gruppe 1
+Vorname2 Nachname2 — Gruppe 1
+
+0
+2 Pl.
diff --git a/libs/Strukturdaten.py b/libs/Strukturdaten.py
index b733ccb..ea89fcf 100755
--- a/libs/Strukturdaten.py
+++ b/libs/Strukturdaten.py
@@ -14,6 +14,7 @@ from random import *
import ast
import configparser, os
import copy
+import html
import math
from collections import defaultdict
from functools import total_ordering
@@ -605,7 +606,8 @@ class Sitzplatzverteilung:
'#42d4f4', '#f032e6', '#bfef45', '#fabed4', '#469990',
'#dcbeff', '#9a6324', '#800000', '#aaffc3', '#000075' ]
- def alsSVG(self, OutputSVG, PersonenRadius=12, Puffer=10, Verbindungen=True):
+ def alsSVG(self, OutputSVG, PersonenRadius=12, Puffer=10, Verbindungen=True,
+ GruppenNamen=None):
"""Zeichnet die Sitzplatzverteilung als SVG:
Tische werden als weisse Kreise dargestellt, Personen als
@@ -617,7 +619,24 @@ class Sitzplatzverteilung:
Ist Verbindungen=True (Vorgabe), wird jede ueber mehrere Tische
getrennte Gruppe zusaetzlich mit einer Linie in ihrer Gruppenfarbe
verbunden, so dass die Zusammengehoerigkeit sichtbar bleibt.
+
+ Jeder Personenkreis bekommt ein
-Kind (nativer Browser-
+ Tooltip beim Hover: "Vorname Nachname — Gruppe") sowie die Attribute
+ class="person" und data-gruppe/data-gid, damit eine einbettende
+ Seite darauf ein Hover-/Kasten-Verhalten aufsetzen kann. Optional
+ liefert GruppenNamen ({Gid: Anzeigename}) die lesbaren Gruppennamen;
+ fehlt es, wird "Gruppe " verwendet.
"""
+ GruppenNamen = GruppenNamen or {}
+
+ def GruppenName(G):
+ if G is None:
+ return 'VIP / feste Platzierung'
+ return GruppenNamen.get( G.Id, 'Gruppe %s' % G.Id )
+
+ def PersonName(P):
+ Teile = [ t for t in (P._Titel, P._Vorname, P._Name) if t ]
+ return ' '.join( Teile )
# Tischradius je Tisch berechnen: gross genug, damit alle
# Personenkreise (auf einem inneren Kreis gleichmaessig verteilt)
# nebeneinander Platz haben, ohne sich zu beruehren. Der Faktor
@@ -757,28 +776,49 @@ class Sitzplatzverteilung:
Winkel = 2 * math.pi * i / max(n, 1) - math.pi / 2
Px = Mx + SitzRadius * math.cos(Winkel)
Py = My + SitzRadius * math.sin(Winkel)
- Farbe = FarbeVonGruppe( GruppeVonPerson(P) )
+ G = GruppeVonPerson(P)
+ Farbe = FarbeVonGruppe( G )
+ GName = GruppenName( G )
+ PName = PersonName( P )
+ # data-gid: -1 fuer VIPs/ohne Gruppe (keine self.Gruppen-Id)
+ Gid = G.Id if G is not None else -1
Teile.append(
- '\n'
- % (Px, Py, PersonenRadius, Farbe) )
+ '%s — %s'
+ '\n'
+ % ( Gid, html.escape(GName, quote=True),
+ html.escape(PName, quote=True),
+ Px, Py, PersonenRadius, Farbe,
+ html.escape(PName), html.escape(GName) ) )
- # Tischnummer zentriert in die Tischmitte (nach den Personen-
- # kreisen gezeichnet, damit sie oben liegt; ein halbtransparenter
- # weisser Kreis darunter haelt sie auch ueber Personenkreisen
- # lesbar, falls die Tischmitte belegt sein sollte)
+ # Tischnummer und Platzzahl zentriert in die Tischmitte (nach den
+ # Personenkreisen gezeichnet, damit sie oben liegen; eine halb-
+ # transparente weisse Ellipse darunter haelt beide Zeilen auch
+ # ueber Personenkreisen lesbar, falls die Tischmitte belegt ist).
+ # Obere Zeile: Tischnummer (gross/fett), darunter die Platzzahl.
Teile.append(
- '\n' % (Mx, My, PersonenRadius) )
+ '\n'
+ % (Mx, My, PersonenRadius, PersonenRadius * 1.3) )
Teile.append(
'%s\n'
- % (Mx, My, PersonenRadius * 1.1, T.Nummer) )
+ % (Mx, My - PersonenRadius * 0.4, PersonenRadius * 1.1, T.Nummer) )
+ Teile.append(
+ '%d Pl.\n'
+ % (Mx, My + PersonenRadius * 0.7, PersonenRadius * 0.62, T.Plaetze) )
Teile.append( '\n' )
- fout = open( OutputSVG, 'w' )
+ # als UTF-8 schreiben (die SVG deklariert encoding="UTF-8"): Namen
+ # enthalten Umlaute und der Gedankenstrich im ist non-ASCII;
+ # ohne dies wuerde die Windows-Standardkodierung (cp1252) die Datei
+ # ungueltig machen.
+ fout = open( OutputSVG, 'w', encoding='utf-8' )
fout.writelines( Teile )
fout.close()
diff --git a/libs/platz.py b/libs/platz.py
index 0e68d67..5115273 100755
--- a/libs/platz.py
+++ b/libs/platz.py
@@ -127,7 +127,8 @@ if __name__ == '__main__':
print(S)
S.speichern( AusgabeTP, AusgabePT )
if options.tosvg:
- S.alsSVG( AusgabeSVG, Verbindungen=options.showconn )
+ S.alsSVG( AusgabeSVG, Verbindungen=options.showconn,
+ GruppenNamen=GruppenNamen )
if options.showdev:
F1.Entwicklung.alsSVG( AusgabeEntwicklung )
print( "Entwicklungsverlauf geschrieben:", AusgabeEntwicklung )
diff --git a/web/main.py b/web/main.py
index 562bfb2..866d617 100644
--- a/web/main.py
+++ b/web/main.py
@@ -518,7 +518,8 @@ def ErgebnisSVG(SitzungsId: str,
Handle, TempPfad = tempfile.mkstemp( suffix='.svg' )
os.close( Handle )
try:
- S['ergebnisse'][variante - 1].alsSVG( TempPfad )
+ S['ergebnisse'][variante - 1].alsSVG( TempPfad,
+ GruppenNamen=S.get( 'gruppenNamen', {} ) )
fsock = open( TempPfad, 'r' )
SVG = fsock.read()
fsock.close()
diff --git a/web/static/index.html b/web/static/index.html
index 504e984..b806e45 100644
--- a/web/static/index.html
+++ b/web/static/index.html
@@ -47,8 +47,16 @@
.status { font-size: .85rem; margin-top: .5rem; min-height: 1.2rem; }
.status.ok { color: var(--akzent); }
.status.fehler { color: #a03030; white-space: pre-wrap; }
- #svgBild { max-width: 100%; border: 1px solid var(--rand); border-radius: 4px;
- margin-top: .75rem; background: white; }
+ #svgPlan { margin-top: .75rem; border: 1px solid var(--rand); border-radius: 4px;
+ background: white; overflow: auto; }
+ #svgPlan svg { max-width: 100%; height: auto; display: block; }
+ #svgPlan .person { cursor: pointer; }
+ #svgPlan .person.aktiv { stroke: #111; stroke-width: 3; }
+ #gruppeBox { position: fixed; z-index: 1000; pointer-events: none; display: none;
+ background: #2a2a24; color: white; border-radius: 6px;
+ padding: .5rem .7rem; font-size: .8rem; max-width: 18rem;
+ line-height: 1.35; box-shadow: 0 2px 10px rgba(0,0,0,.35); }
+ #gruppeBox b { display: block; margin-bottom: .3rem; color: var(--akzent-hell, #d6eade); }
.kennzahl { display: inline-block; background: #f1eee6; border-radius: 4px;
padding: .3rem .7rem; margin: .15rem .3rem .15rem 0; font-size: .9rem; }
.kennzahl b { color: var(--akzent); }
@@ -125,9 +133,13 @@
+
Im Raumplan mit der Maus über eine Person
+ fahren: Tooltip zeigt Name & Gruppe, ein Kasten listet alle Namen dieser Gruppe,
+ und die Gruppe wird im Plan hervorgehoben.