#!/usr/bin/env python # coding: utf-8 # # Simple Jupyter Canvas # # Need a way to draw on Javascript canvas straightforwardly. # ## Minimum Viable # # Simply create a canvas object and write to it. # In[38]: #canvas code via https://jsfiddle.net/macloo/JLVva/ class Canvas0(object): def __init__(self,cc): self.canvas_code=cc def _repr_html_(self): return self.canvas_code txt='''
Triangles!
''' Canvas0(txt) # ## Start to Pull Out Some Construction Methods # # What methods can we sensibly extract? # # In[260]: class Canvas1(object): def __init__(self,script,cid='mytag', context=None): self.cid=cid self.context = context if context else 'ctx' self.wrap = context is None self._html =[] self._add_canvas(cid) self._get_canvas() self._add_script_tag(script) def _add_canvas(self, cid): html=''''''.format(cid) self._html.append(html) def _get_canvas(self): script = ''' '''.format(cid = self.cid, ctx=self.context) self._html.append(script) def _add_script_tag(self, script): if self.wrap: self._html.append(''.format(self.context,script)) else: self._html.append(''.format(script)) def html(self): return '\n'.join(self._html) def _repr_html_(self): return self.html() txt=''' ctx.beginPath(); // note usage below // triangle 1, at left ctx.fillStyle = "#F9A520"; ctx.moveTo(0, 0); // start at top left corner of canvas ctx.lineTo(200, 0); // go 200px to right (x), straight line from 0 to 0 ctx.lineTo(100, 200); // go to horizontal 100 (x) and vertical 200 (y) ctx.fill(); // connect and fill // triangle 2, top center ctx.moveTo(300, 0); // pick up "pen," reposition at 300 (horiz), 0 (vert) ctx.lineTo(300, 200); // draw straight down (from 300,0) to 200px ctx.lineTo(500, 100); // draw up toward right (100 half of 200) ctx.fill(); // connect and fill // triangle 3, bottom center ctx.beginPath(); // note: w/o this, color does not work as expected ctx.fillStyle = "#F00"; ctx.moveTo(300, 200); // pick up "pen," reposition at 300 (horiz), 200 (vert) ctx.lineTo(300, 400); // draw straight down by 200px (200 + 200) ctx.lineTo(100, 300); // draw up toward left (100 less than 300, so left) ctx.fill(); // connect and fill ''' txt2=''' beginPath(); // note usage below // triangle 1, at left fillStyle = "#F9A520"; moveTo(0, 0); // start at top left corner of canvas lineTo(200, 0); // go 200px to right (x), straight line from 0 to 0 lineTo(100, 200); // go to horizontal 100 (x) and vertical 200 (y) fill(); // connect and fill // triangle 3, bottom center beginPath(); // note: w/o this, color does not work as expected fillStyle = "#F00"; moveTo(300, 200); // pick up "pen," reposition at 300 (horiz), 200 (vert) lineTo(300, 400); // draw straight down by 200px (200 + 200) lineTo(100, 300); // draw up toward left (100 less than 300, so left) fill(); // connect and fill ''' Canvas1(txt, context= 'ctx') #Canvas1(txt2) # Let's have a go at creating some magic... # In[283]: import random import string import shlex from argparse import ArgumentParser from IPython.core.magic import ( magics_class, line_cell_magic, Magics) from IPython.core.display import HTML @magics_class class CanvasMagic(Magics): def __init__(self, shell, cache_display_data=False): super(CanvasMagic, self).__init__(shell) self.cache_display_data = cache_display_data @line_cell_magic def canvas(self,line, cell=''): '''Run JS canvas commands.''' parser = ArgumentParser() parser.add_argument('-c', '--context', default=None) parser.add_argument('-I', '--id', default=None) parser.add_argument('--wrap', dest='wrap_env', action='store_true') parser.add_argument('--no-wrap', dest='wrap_env', action='store_false') parser.add_argument('-v', '--variable', default=None) parser.set_defaults(wrap_env=False) args = parser.parse_args(shlex.split(line)) if args.variable: cell = self.shell.user_ns[args.variable] #Create a random id for the canvas tag to try to prevent clashes argsid = args.id if args.id else ''.join(random.choices(string.ascii_uppercase + string.digits, k=5)) if not args.context: if not args.wrap_env: context = None else: context='ctx' else: context = args.context #We need to add the extra \n in case the last line in the cell is a comment that would comment out return Canvas1(cell+'\n', context=context, cid=argsid) # In[284]: ip = get_ipython() ip.register_magics(CanvasMagic) # In[285]: get_ipython().run_cell_magic('canvas', '-c ctx', 'ctx.beginPath(); \n\nctx.fillStyle = "#F9A520";\nctx.moveTo(0, 0);\nctx.lineTo(200, 0); \nctx.lineTo(100, 200); \nctx.fill(); \n\n// triangle 2, top center\nctx.moveTo(300, 0); // pick up "pen," reposition at 300 (horiz), 0 (vert)\nctx.lineTo(300, 200); // draw straight down (from 300,0) to 200px\nctx.lineTo(500, 100); // draw up toward right (100 half of 200)\nctx.fill(); // connect and fill\n\nctx.stroke(); \n') # In[286]: get_ipython().run_cell_magic('canvas', '', 'beginPath(); \n\nfillStyle = "#F9A520";\nmoveTo(0, 0);\nlineTo(200, 0); \nlineTo(100, 200); \nfill(); \n\nbeginPath(); \nfillStyle = "#F00";\nmoveTo(300, 200); \nlineTo(300, 400); // draw straight down by 200px (200 + 200)\nlineTo(100, 300); // draw up toward left (100 less than 300, so left)\nfill(); // connect and fill\n') # In[288]: get_ipython().run_line_magic('canvas', '-v txt2') # In[289]: get_ipython().run_line_magic('canvas', '-v txt --context ctx') # In[ ]: