Skip to content

Commit 3ec9f79

Browse files
committed
Cache commands
1 parent 94230c1 commit 3ec9f79

File tree

3 files changed

+78
-59
lines changed

3 files changed

+78
-59
lines changed

examples/introduction.ipynb

Lines changed: 15 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,7 @@
5050
"outputs": [],
5151
"source": [
5252
"c = ipycanvas.Canvas(stroke_style='red', size=(200, 200))\n",
53-
"c"
54-
]
55-
},
56-
{
57-
"cell_type": "code",
58-
"execution_count": null,
59-
"metadata": {},
60-
"outputs": [],
61-
"source": [
53+
"\n",
6254
"# Draw smiley face\n",
6355
"c.begin_path()\n",
6456
"c.arc(75, 75, 50, 0, pi * 2, True) # Outer circle\n",
@@ -68,7 +60,9 @@
6860
"c.arc(60, 65, 5, 0, pi * 2, True) # Left eye\n",
6961
"c.move_to(95, 65)\n",
7062
"c.arc(90, 65, 5, 0, pi * 2, True) # Right eye\n",
71-
"c.stroke()"
63+
"c.stroke()\n",
64+
"\n",
65+
"c"
7266
]
7367
},
7468
{
@@ -77,8 +71,6 @@
7771
"metadata": {},
7872
"outputs": [],
7973
"source": [
80-
"c = ipycanvas.Canvas(size=(200, 200))\n",
81-
"\n",
8274
"c"
8375
]
8476
},
@@ -88,6 +80,8 @@
8880
"metadata": {},
8981
"outputs": [],
9082
"source": [
83+
"c = ipycanvas.Canvas(size=(200, 200))\n",
84+
"\n",
9185
"# Draw bubble\n",
9286
"c.begin_path()\n",
9387
"c.move_to(75, 25)\n",
@@ -97,16 +91,7 @@
9791
"c.quadratic_curve_to(60, 120, 65, 100)\n",
9892
"c.quadratic_curve_to(125, 100, 125, 62.5)\n",
9993
"c.quadratic_curve_to(125, 25, 75, 25)\n",
100-
"c.stroke()"
101-
]
102-
},
103-
{
104-
"cell_type": "code",
105-
"execution_count": null,
106-
"metadata": {},
107-
"outputs": [],
108-
"source": [
109-
"c = ipycanvas.Canvas(size=(150, 150))\n",
94+
"c.stroke()\n",
11095
"\n",
11196
"c"
11297
]
@@ -137,6 +122,8 @@
137122
"metadata": {},
138123
"outputs": [],
139124
"source": [
125+
"c = ipycanvas.Canvas(size=(150, 150))\n",
126+
"\n",
140127
"rounded_rect(c, 12, 12, 150, 150, 15)\n",
141128
"rounded_rect(c, 19, 19, 150, 150, 9)\n",
142129
"rounded_rect(c, 53, 53, 49, 33, 10)\n",
@@ -193,16 +180,7 @@
193180
"\n",
194181
"c.begin_path()\n",
195182
"c.arc(89, 102, 2, 0, pi * 2, True)\n",
196-
"c.fill()"
197-
]
198-
},
199-
{
200-
"cell_type": "code",
201-
"execution_count": null,
202-
"metadata": {},
203-
"outputs": [],
204-
"source": [
205-
"c = ipycanvas.Canvas(size=(150, 150))\n",
183+
"c.fill()\n",
206184
"\n",
207185
"c"
208186
]
@@ -213,6 +191,8 @@
213191
"metadata": {},
214192
"outputs": [],
215193
"source": [
194+
"c = ipycanvas.Canvas(size=(150, 150))\n",
195+
"\n",
216196
"# Draw background\n",
217197
"c.fill_style = '#FD0'\n",
218198
"c.fill_rect(0, 0, 75, 75)\n",
@@ -231,7 +211,9 @@
231211
"for i in range(7):\n",
232212
" c.begin_path();\n",
233213
" c.arc(75, 75, 10 + 10 * i, 0, pi * 2, True);\n",
234-
" c.fill();"
214+
" c.fill();\n",
215+
"\n",
216+
"c"
235217
]
236218
}
237219
],

ipycanvas/canvas.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -33,50 +33,50 @@ def __init__(self, *args, **kwargs):
3333
# Rectangles methods
3434
def fill_rect(self, x, y, width, height):
3535
"""Draw a filled rectangle."""
36-
self._send_canvas_msg('fillRect', x, y, width, height)
36+
self._send_canvas_command('fillRect', x, y, width, height)
3737

3838
def stroke_rect(self, x, y, width, height):
3939
"""Draw a rectangular outline."""
40-
self._send_canvas_msg('strokeRect', x, y, width, height)
40+
self._send_canvas_command('strokeRect', x, y, width, height)
4141

4242
def clear_rect(self, x, y, width, height):
4343
"""Clear the specified rectangular area, making it fully transparent."""
44-
self._send_canvas_msg('clearRect', x, y, width, height)
44+
self._send_canvas_command('clearRect', x, y, width, height)
4545

4646
def rect(self, x, y, width, height):
4747
"""Draw a rectangle whose top-left corner is specified by (x, y) with the specified width and height."""
48-
self._send_canvas_msg('rect', x, y, width, height)
48+
self._send_canvas_command('rect', x, y, width, height)
4949

5050
# Paths methods
5151
def begin_path(self):
52-
self._send_canvas_msg('beginPath')
52+
self._send_canvas_command('beginPath')
5353

5454
def close_path(self):
55-
self._send_canvas_msg('closePath')
55+
self._send_canvas_command('closePath')
5656

5757
def stroke(self):
58-
self._send_canvas_msg('stroke')
58+
self._send_canvas_command('stroke')
5959

6060
def fill(self):
61-
self._send_canvas_msg('fill')
61+
self._send_canvas_command('fill')
6262

6363
def move_to(self, x, y):
64-
self._send_canvas_msg('moveTo', x, y)
64+
self._send_canvas_command('moveTo', x, y)
6565

6666
def line_to(self, x, y):
67-
self._send_canvas_msg('lineTo', x, y)
67+
self._send_canvas_command('lineTo', x, y)
6868

6969
def arc(self, x, y, radius, start_angle, end_angle, anticlockwise):
70-
self._send_canvas_msg('arc', x, y, radius, start_angle, end_angle, anticlockwise)
70+
self._send_canvas_command('arc', x, y, radius, start_angle, end_angle, anticlockwise)
7171

7272
def arc_to(self, x1, y1, x2, y2, radius):
73-
self._send_canvas_msg('arcTo', x1, y1, x2, y2, radius)
73+
self._send_canvas_command('arcTo', x1, y1, x2, y2, radius)
7474

7575
def quadratic_curve_to(self, cp1x, cp1y, x, y):
76-
self._send_canvas_msg('quadraticCurveTo', cp1x, cp1y, x, y)
76+
self._send_canvas_command('quadraticCurveTo', cp1x, cp1y, x, y)
7777

7878
def bezier_curve_to(self, cp1x, cp1y, cp2x, cp2y, x, y):
79-
self._send_canvas_msg('bezierCurveTo', cp1x, cp1y, cp2x, cp2y, x, y)
79+
self._send_canvas_command('bezierCurveTo', cp1x, cp1y, cp2x, cp2y, x, y)
8080

81-
def _send_canvas_msg(self, msg_name, *args):
82-
self.send({'msg': msg_name, 'args': args})
81+
def _send_canvas_command(self, name, *args):
82+
self.send({'name': name, 'args': args})

src/widget.ts

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,42 @@ class CanvasModel extends DOMWidgetModel {
2929
}
3030

3131
static serializers: ISerializers = {
32-
...DOMWidgetModel.serializers,
33-
// Add any extra serializers here
34-
}
32+
...DOMWidgetModel.serializers,
33+
// Add any extra serializers here
34+
}
35+
36+
initialize(attributes: any, options: any) {
37+
super.initialize(attributes, options);
38+
39+
this.commands_cache = [];
40+
41+
this.cache_set_command('fill_style', 'fillStyle');
42+
this.cache_set_command('stroke_style', 'strokeStyle');
43+
this.cache_set_command('global_alpha', 'globalAlpha');
44+
45+
this.on('msg:custom', (command) => { this.commands_cache.push(command); });
46+
47+
this.on('change:fill_style', () => { this.cache_set_command('fill_style', 'fillStyle'); });
48+
this.on('change:stroke_style', () => { this.cache_set_command('stroke_style', 'strokeStyle'); });
49+
this.on('change:global_alpha', () => { this.cache_set_command('global_alpha', 'globalAlpha'); });
50+
}
51+
52+
cache_set_command(python_name: string, ts_name: string) {
53+
this.commands_cache.push({
54+
name: 'set',
55+
attr: ts_name,
56+
value: this.get(python_name)
57+
});
58+
}
3559

3660
static model_name = 'CanvasModel';
3761
static model_module = MODULE_NAME;
3862
static model_module_version = MODULE_VERSION;
3963
static view_name = 'CanvasView';
4064
static view_module = MODULE_NAME;
4165
static view_module_version = MODULE_VERSION;
66+
67+
commands_cache: any;
4268
}
4369

4470

@@ -53,22 +79,33 @@ class CanvasView extends DOMWidgetView {
5379

5480
this.ctx = this.canvas.getContext('2d');
5581

56-
this.ctx.globalAlpha = this.model.get('global_alpha');
57-
5882
this.resize_canvas();
5983

84+
this.first_draw();
85+
6086
this.model_events();
6187
}
6288

63-
model_events() {
64-
this.model.on('msg:custom', (event) => {
65-
this.ctx.fillStyle = this.model.get('fill_style');
66-
this.ctx.strokeStyle = this.model.get('stroke_style');
89+
first_draw() {
90+
// Replay all the commands that were received until this view was created
91+
for (const command of (this.model as CanvasModel).commands_cache) {
92+
if (command.name == 'set') {
93+
this.ctx[command.attr] = command.value;
94+
} else {
95+
this.ctx[command.name](...command.args);
96+
}
97+
}
98+
}
6799

68-
this.ctx[event.msg](...event.args);
100+
model_events() {
101+
this.model.on('msg:custom', (command) => {
102+
this.ctx[command.name](...command.args);
69103
});
70104

71105
this.model.on('change:size', () => { this.resize_canvas(); });
106+
107+
this.model.on('change:fill_style', () => { this.ctx.fillStyle = this.model.get('fill_style'); });
108+
this.model.on('change:stroke_style', () => { this.ctx.strokeStyle = this.model.get('stroke_style'); });
72109
this.model.on('change:global_alpha', () => { this.ctx.globalAlpha = this.model.get('global_alpha'); });
73110
}
74111

0 commit comments

Comments
 (0)