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 | """
A web app that allows multiple people to colaborate in painting. People
connecting later will not see the "paint" that was added earlier. Each
person is assigned a random color which affects how that person can
best contribute to the painting.
This app might be running at the demo server: http://flexx1.zoof.io
"""
import random
from flexx import flx
COLORS = ('#eee', '#999', '#555', '#111',
'#f00', '#0f0', '#00f', '#ff0', '#f0f', '#0ff',
'#a44', '#4a4', '#44a', '#aa4', '#afa', '#4aa',
)
class Relay(flx.Component):
""" Global object to relay paint events to all participants.
"""
@flx.emitter
def add_paint_for_all(self, pos, color):
return dict(pos=pos, color=color)
# Create global relay object, shared by all connections
relay = Relay()
class ColabPainting(flx.PyComponent):
""" The Python side of the app. There is one instance per connection.
"""
color = flx.ColorProp(settable=True, doc="Paint color")
status = flx.StringProp('', settable=True, doc="Status text")
def init(self):
self.set_color(random.choice(COLORS))
self.widget = ColabPaintingView(self)
self._update_participants()
@flx.action
def add_paint(self, pos):
""" Add paint at the specified position.
"""
relay.add_paint_for_all(pos, self.color.hex)
@relay.reaction('add_paint_for_all') # note that we connect to relay here
def _any_user_adds_paint(self, *events):
""" Receive global paint event from the relay, invoke action on view.
"""
for ev in events:
self.widget.add_paint_to_canvas(ev.pos, ev.color)
@flx.manager.reaction('connections_changed')
def _update_participants(self, *events):
if self.session.status:
sessions = flx.manager.get_connections(self.session.app_name)
n = len(sessions)
del sessions
self.set_status('%i persons are painting' % n)
class ColabPaintingView(flx.Widget):
""" The part of the app that runs in the browser.
"""
CSS = """
.flx-ColabPaintingView { background: #ddd; }
.flx-ColabPaintingView .flx-CanvasWidget {
background: #fff;
border: 10px solid #000;
}
"""
def init(self, model):
super().init()
self.model = model
# App layout
with flx.VBox():
flx.Label(flex=0, text=lambda: model.status)
flx.Widget(flex=1)
with flx.HBox(flex=2):
flx.Widget(flex=1)
self.canvas = flx.CanvasWidget(flex=0, minsize=400, maxsize=400)
flx.Widget(flex=1)
flx.Widget(flex=1)
# Init context to draw to
self._ctx = self.canvas.node.getContext('2d')
@flx.reaction
def __update_color(self):
self.canvas.apply_style('border: 10px solid ' + self.model.color.hex)
@flx.reaction('canvas.pointer_down')
def __on_click(self, *events):
for ev in events:
self.model.add_paint(ev.pos)
@flx.action
def add_paint_to_canvas(self, pos, color):
""" Actually draw a dot on the canvas.
"""
self._ctx.globalAlpha = 0.8
self._ctx.beginPath()
self._ctx.fillStyle = color
self._ctx.arc(pos[0], pos[1], 5, 0, 6.2831)
self._ctx.fill()
if __name__ == '__main__':
a = flx.App(ColabPainting)
a.serve()
# m = a.launch('browser') # for use during development
flx.start()
|