Skip to content

Commit 98c9d08

Browse files
Adding an example from Andries
This example show how to draw boxes and connection arrows.
1 parent 6173dd1 commit 98c9d08

1 file changed

Lines changed: 240 additions & 0 deletions

File tree

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
import remi.gui as gui
2+
from remi import start, App
3+
import math
4+
5+
class SvgPolygon(gui.SvgPolyline):
6+
def __init__(self, _maxlen=None, *args, **kwargs):
7+
super(SvgPolygon, self).__init__(_maxlen, *args, **kwargs)
8+
self.type = 'polygon'
9+
10+
def set_stroke(self, width=1, color='black'):
11+
"""Sets the stroke properties.
12+
13+
Args:
14+
width (int): stroke width
15+
color (str): stroke color
16+
"""
17+
self.attributes['stroke'] = color
18+
self.attributes['stroke-width'] = str(width)
19+
20+
def set_fill(self, color='black'):
21+
"""Sets the fill color.
22+
23+
Args:
24+
color (str): stroke color
25+
"""
26+
self.style['fill'] = color
27+
self.attributes['fill'] = color
28+
29+
def add_arrow_coord(self, line, arrow_height, arrow_width, recess):
30+
""" Determine the coordinates of an arrow head polygon
31+
with height (h) and width (w) and recess (r)
32+
pointing from the one but last to the last point of (poly)line (line).
33+
Note that the coordinates of an SvgLine and an SvgPolyline
34+
are stored in different variables.
35+
"""
36+
# arrow = SvgPolygon(_maxlen=4)
37+
if line.type == 'polyline':
38+
xe = line.coordsX[-1]
39+
ye = line.coordsY[-1]
40+
xp = line.coordsX[-2]
41+
yp = line.coordsY[-2]
42+
else:
43+
xe = line.attributes['x2']
44+
ye = line.attributes['y2']
45+
xp = line.attributes['x1']
46+
yp = line.attributes['y1']
47+
h = arrow_height
48+
if arrow_width == 0:
49+
w = arrow_height / 3
50+
else:
51+
w = arrow_width
52+
r = recess
53+
self.add_coord(xe, ye)
54+
dx = xe - xp
55+
dy = ye - yp
56+
de = math.sqrt(dx**2 + dy**2)
57+
xh = xe - h * dx / de
58+
yh = ye - h * dy / de
59+
x1 = xh + w * dy / de
60+
y1 = yh - w * dx / de
61+
self.add_coord(x1, y1)
62+
x2 = xe - (h - r) * dx / de
63+
y2 = ye - (h - r) * dy / de
64+
self.add_coord(x2, y2)
65+
x3 = xh - w * dy / de
66+
y3 = yh + w * dx / de
67+
self.add_coord(x3, y3)
68+
69+
70+
class MyApp(App):
71+
""" Example drawing by Andries van Renssen
72+
including connected rectangular boxes, polylines and rhombusses.
73+
"""
74+
def __init__(self, *args):
75+
super(MyApp, self).__init__(*args)
76+
77+
def main(self):
78+
self.frame = gui.VBox(width='100%', height='80%',
79+
style={'overflow': 'auto',
80+
'background-color': '#eeffdd'})
81+
self.sheet = gui.Svg(width='100%', height='100%')
82+
self.screen_width = 1000
83+
self.screen_height = 600
84+
self.int_id = 0
85+
self.sheet.set_viewbox(0, 0, self.screen_width, self.screen_height)
86+
self.frame.append(self.sheet)
87+
nr_of_boxes = 2
88+
box_names = ['Activity-A', 'Activity-B']
89+
self.Draw_a_drawing_of_one_sheet(nr_of_boxes, box_names)
90+
return self.frame
91+
92+
def Draw_a_drawing_of_one_sheet(self, nr_of_boxes, box_names):
93+
""" Draw a drawing with two boxes, each with a name inside
94+
and a polyline between the midpoints of the sides of the boxes,
95+
with half-way the polyline a rhombus with an id included.
96+
"""
97+
thickness = 2 # Line thickness
98+
center_x = [] # x of the center of box[i] on canvas
99+
center_y = [] # y of the center of box[i] on canvas
100+
mid_points = []
101+
box_width = 100 # pixels
102+
box_height = 100 # pixels
103+
delta_x = self.screen_width / (nr_of_boxes + 1)
104+
delta_y = self.screen_height / (nr_of_boxes + 1)
105+
# Draw the boxes
106+
for box_nr in range(0, nr_of_boxes):
107+
center_x.append(delta_x + box_nr * delta_x)
108+
center_y.append(delta_y + box_nr * delta_y)
109+
name = box_names[box_nr]
110+
ident = str(box_nr + 1)
111+
# Draw one box at the specified location
112+
mid_points.append(self.box_type_1(
113+
center_x[box_nr], center_y[box_nr],
114+
name, ident, box_width,box_height))
115+
116+
# Draw a line with arrow head to the first box
117+
x2 = mid_points[0][3][0]
118+
y2 = mid_points[0][3][1]
119+
x1 = x2 - 150
120+
y1 = y2
121+
line_0 = gui.SvgLine(x1, y1, x2, y2)
122+
line_0.set_stroke(width=thickness, color='black')
123+
self.sheet.append(line_0)
124+
# Add an arrow head to line_0
125+
head_0 = SvgPolygon(4)
126+
arrow_height = 20
127+
arrow_width = arrow_height / 3
128+
recess = arrow_height / 5
129+
head_0.add_arrow_coord(line_0, arrow_height, arrow_width, recess)
130+
head_0.set_stroke(width=thickness, color='black')
131+
head_0.set_fill(color='blue')
132+
self.sheet.append(head_0)
133+
134+
# Draw a rhombus polygon
135+
x = (center_x[0] + center_x[1]) / 2
136+
y = (center_y[0] + center_y[1]) / 2
137+
self.int_id += 1
138+
str_id = str(self.int_id)
139+
hor_size = 15 # pixels
140+
vert_size = 25 # pixels
141+
rhombus = self.rhombus_polygon(x, y, str_id, hor_size, vert_size)
142+
143+
# Determine points of the first polyline
144+
line_1_points = []
145+
line_1_points.append(mid_points[0][2])
146+
corner = [rhombus[0][0], mid_points[0][2][1]]
147+
line_1_points.append(corner)
148+
line_1_points.append(rhombus[0])
149+
# Draw a polyline from box_1 to rhombus
150+
line1 = gui.SvgPolyline(_maxlen=4)
151+
for pt in line_1_points:
152+
line1.add_coord(*pt)
153+
line1.set_stroke(width=thickness, color='black')
154+
self.sheet.append(line1)
155+
156+
# Determine points of the second polyline
157+
line_2_points = []
158+
line_2_points.append(rhombus[1])
159+
corner = [rhombus[1][0], mid_points[1][3][1]]
160+
line_2_points.append(corner)
161+
line_2_points.append(mid_points[1][3])
162+
# Drawa polyline from rhombus to box_2
163+
line2 = gui.SvgPolyline(_maxlen=4)
164+
for pt in line_2_points:
165+
line2.add_coord(pt[0], pt[1])
166+
line2.set_stroke(width=thickness, color='black')
167+
self.sheet.append(line2)
168+
169+
# Add an arrow head to line2
170+
head = SvgPolygon(4)
171+
head.add_arrow_coord(line2, arrow_height, arrow_width, recess)
172+
head.set_stroke(width=thickness, color='black')
173+
head.set_fill(color='blue')
174+
self.sheet.append(head)
175+
176+
def box_type_1(self, X, Y, name, ident, box_width, box_height):
177+
""" Draw a rectangular box of box_width and box_height
178+
with name and ident,
179+
on sheet with (X,Y) as its center on the canvas
180+
Return midpts = N(x,y), S(x,y), E(x,y), W(x,y).
181+
"""
182+
boxW2 = box_width / 2
183+
boxH2 = box_height / 2
184+
x0, y0 = X - boxW2, Y - boxH2 # Top_left of box
185+
x1, y1 = X + boxW2, Y + boxH2 # Bottom_right of box
186+
width = x1 - x0
187+
height = y1 - y0
188+
189+
box = gui.SvgRectangle(x0, y0, width, height)
190+
box.set_stroke(width=2, color='black')
191+
box.set_fill(color='yellow')
192+
box_name = gui.SvgText(X, Y, name)
193+
box_name.attributes['text-anchor'] = 'middle'
194+
box_id = gui.SvgText(X, Y + 15, str(ident))
195+
box_id.attributes['text-anchor'] = 'middle'
196+
self.sheet.append([box, box_name, box_id])
197+
198+
mid_north = [X, Y - boxH2]
199+
mid_south = [X, Y + boxH2]
200+
mid_east = [X + boxW2, Y]
201+
mid_west = [X - boxW2, Y]
202+
203+
return mid_north, mid_south, mid_east, mid_west
204+
205+
def rhombus_polygon(self, X, Y, str_id, hor_size, vert_size):
206+
""" Draw a rhombus polygon.
207+
Horizontal size (-hor_size, +hor_size) and
208+
vertical size (-vert_size, +vert_size).
209+
with its center on position X,Y
210+
and with its str_id as text in the middle.
211+
"""
212+
x0, y0 = X - hor_size, Y # mid_west
213+
x1, y1 = X, Y - vert_size # mid_north
214+
x2, y2 = X + hor_size, Y # mid_east
215+
x3, y3 = X, Y + vert_size # mid_south
216+
217+
polygon = SvgPolygon(4)
218+
polygon.set_stroke(width=2, color='black')
219+
poly_name = gui.SvgText(X, Y + 5, str_id)
220+
poly_name.attributes['text-anchor'] = 'middle'
221+
self.sheet.append([polygon, poly_name])
222+
223+
mid_north = [x1, y1]
224+
mid_south = [x3, y3]
225+
mid_east = [x2, y2]
226+
mid_west = [x0, y0]
227+
228+
polygon.add_coord(*mid_north)
229+
polygon.add_coord(*mid_east)
230+
polygon.add_coord(*mid_south)
231+
polygon.add_coord(*mid_west)
232+
233+
return mid_north, mid_south, mid_east, mid_west
234+
235+
if __name__ == "__main__":
236+
# starts the webserver
237+
# optional parameters
238+
start(MyApp,address='127.0.0.1', port=8081, multiple_instance=False,
239+
enable_file_cache=True, update_interval=0.1, start_browser=True)
240+
# start(MyApp, debug=True, address='0.0.0.0', port=0 )

0 commit comments

Comments
 (0)