Skip to content

Instantly share code, notes, and snippets.

@psychemedia
Last active January 14, 2018 14:57
Show Gist options
  • Select an option

  • Save psychemedia/bddbbb09b466abd78e8c293591b6319a to your computer and use it in GitHub Desktop.

Select an option

Save psychemedia/bddbbb09b466abd78e8c293591b6319a to your computer and use it in GitHub Desktop.
Sketches around js canvas, incl simple magic
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Simple Jupyter Canvas\n",
"\n",
"Need a way to draw on Javascript canvas straightforwardly."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Minimum Viable\n",
"\n",
"Simply create a canvas object and write to it."
]
},
{
"cell_type": "code",
"execution_count": 38,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<canvas id=\"myCanvas0\" width=\"700\" height=\"410\">\n",
" <p>Some default content can appear here.</p>\n",
"</canvas>\n",
"<p>Triangles!</p>\n",
"<script>function draw() {\n",
" // canvas with id=\"myCanvas\"\n",
" var canvas = document.getElementById('myCanvas0');\n",
" if (canvas.getContext) {\n",
" var ctx = canvas.getContext('2d');\n",
" ctx.beginPath(); // note usage below \n",
"\n",
" // triangle 1, at left\n",
" ctx.fillStyle = \"#F9A520\";\n",
" ctx.moveTo(0, 0); // start at top left corner of canvas\n",
" ctx.lineTo(200, 0); // go 200px to right (x), straight line from 0 to 0\n",
" ctx.lineTo(100, 200); // go to horizontal 100 (x) and vertical 200 (y)\n",
" ctx.fill(); // connect and fill\n",
"\n",
" // triangle 2, top center\n",
" ctx.moveTo(300, 0); // pick up \"pen,\" reposition at 300 (horiz), 0 (vert)\n",
" ctx.lineTo(300, 200); // draw straight down (from 300,0) to 200px\n",
" ctx.lineTo(500, 100); // draw up toward right (100 half of 200)\n",
" ctx.fill(); // connect and fill\n",
"\n",
" // triangle 3, bottom center\n",
" ctx.beginPath(); // note: w/o this, color does not work as expected \n",
" ctx.fillStyle = \"#F00\";\n",
" ctx.moveTo(300, 200); // pick up \"pen,\" reposition at 300 (horiz), 200 (vert)\n",
" ctx.lineTo(300, 400); // draw straight down by 200px (200 + 200)\n",
" ctx.lineTo(100, 300); // draw up toward left (100 less than 300, so left)\n",
" ctx.fill(); // connect and fill\n",
"\n",
" // triangle 4, at right, top\n",
" ctx.beginPath();\n",
" ctx.strokeStyle = \"#00F\";\n",
" ctx.moveTo(600, 0); // pick up \"pen,\" reposition at 500 (horiz), 0 (vert)\n",
" ctx.lineTo(500, 200); // draw straight down by 200px (200 + 200)\n",
" ctx.lineTo(700, 200); // draw up toward left (100 less than 300, so left)\n",
" ctx.closePath(); // connect end to start\n",
" ctx.stroke(); // outline the shape that's been described\n",
"\n",
" // triangle 5, at right, bottom\n",
" ctx.beginPath();\n",
" ctx.strokeStyle = \"#096\";\n",
" ctx.moveTo(500, 210); // pick up \"pen,\" reposition \n",
" ctx.lineTo(700, 210); // draw straight across to right\n",
" ctx.lineTo(600, 410); // draw down toward left\n",
" ctx.closePath(); // connect end to start\n",
" ctx.stroke(); // outline the shape that's been described\n",
"\n",
" }\n",
"}\n",
"\n",
"draw();</script>"
],
"text/plain": [
"<__main__.Canvas0 at 0x1089e5898>"
]
},
"execution_count": 38,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#canvas code via https://jsfiddle.net/macloo/JLVva/\n",
"class Canvas0(object):\n",
" def __init__(self,cc):\n",
" self.canvas_code=cc\n",
" def _repr_html_(self):\n",
" return self.canvas_code\n",
"\n",
"\n",
"txt='''<canvas id=\"myCanvas0\" width=\"700\" height=\"410\">\n",
" <p>Some default content can appear here.</p>\n",
"</canvas>\n",
"<p>Triangles!</p>\n",
"<script>function draw() {\n",
" // canvas with id=\"myCanvas\"\n",
" var canvas = document.getElementById('myCanvas0');\n",
" if (canvas.getContext) {\n",
" var ctx = canvas.getContext('2d');\n",
" ctx.beginPath(); // note usage below \n",
"\n",
" // triangle 1, at left\n",
" ctx.fillStyle = \"#F9A520\";\n",
" ctx.moveTo(0, 0); // start at top left corner of canvas\n",
" ctx.lineTo(200, 0); // go 200px to right (x), straight line from 0 to 0\n",
" ctx.lineTo(100, 200); // go to horizontal 100 (x) and vertical 200 (y)\n",
" ctx.fill(); // connect and fill\n",
"\n",
" // triangle 2, top center\n",
" ctx.moveTo(300, 0); // pick up \"pen,\" reposition at 300 (horiz), 0 (vert)\n",
" ctx.lineTo(300, 200); // draw straight down (from 300,0) to 200px\n",
" ctx.lineTo(500, 100); // draw up toward right (100 half of 200)\n",
" ctx.fill(); // connect and fill\n",
"\n",
" // triangle 3, bottom center\n",
" ctx.beginPath(); // note: w/o this, color does not work as expected \n",
" ctx.fillStyle = \"#F00\";\n",
" ctx.moveTo(300, 200); // pick up \"pen,\" reposition at 300 (horiz), 200 (vert)\n",
" ctx.lineTo(300, 400); // draw straight down by 200px (200 + 200)\n",
" ctx.lineTo(100, 300); // draw up toward left (100 less than 300, so left)\n",
" ctx.fill(); // connect and fill\n",
"\n",
" // triangle 4, at right, top\n",
" ctx.beginPath();\n",
" ctx.strokeStyle = \"#00F\";\n",
" ctx.moveTo(600, 0); // pick up \"pen,\" reposition at 500 (horiz), 0 (vert)\n",
" ctx.lineTo(500, 200); // draw straight down by 200px (200 + 200)\n",
" ctx.lineTo(700, 200); // draw up toward left (100 less than 300, so left)\n",
" ctx.closePath(); // connect end to start\n",
" ctx.stroke(); // outline the shape that's been described\n",
"\n",
" // triangle 5, at right, bottom\n",
" ctx.beginPath();\n",
" ctx.strokeStyle = \"#096\";\n",
" ctx.moveTo(500, 210); // pick up \"pen,\" reposition \n",
" ctx.lineTo(700, 210); // draw straight across to right\n",
" ctx.lineTo(600, 410); // draw down toward left\n",
" ctx.closePath(); // connect end to start\n",
" ctx.stroke(); // outline the shape that's been described\n",
"\n",
" }\n",
"}\n",
"\n",
"draw();</script>'''\n",
"Canvas0(txt)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Start to Pull Out Some Construction Methods\n",
"\n",
"What methods can we sensibly extract?\n"
]
},
{
"cell_type": "code",
"execution_count": 260,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<canvas id=\"mytag\" width=\"700\" height=\"410\"> <p>Some default content can appear here.</p>\n",
"</canvas>\n",
"<script type=\"text/javascript\">var canvas = document.getElementById('mytag');\n",
" //if (canvas.getContext) {}\n",
" var ctx = canvas.getContext('2d');</script> \n",
"<script type=\"text/javascript\">\n",
" ctx.beginPath(); // note usage below \n",
"\n",
" // triangle 1, at left\n",
" ctx.fillStyle = \"#F9A520\";\n",
" ctx.moveTo(0, 0); // start at top left corner of canvas\n",
" ctx.lineTo(200, 0); // go 200px to right (x), straight line from 0 to 0\n",
" ctx.lineTo(100, 200); // go to horizontal 100 (x) and vertical 200 (y)\n",
" ctx.fill(); // connect and fill\n",
"\n",
" // triangle 2, top center\n",
" ctx.moveTo(300, 0); // pick up \"pen,\" reposition at 300 (horiz), 0 (vert)\n",
" ctx.lineTo(300, 200); // draw straight down (from 300,0) to 200px\n",
" ctx.lineTo(500, 100); // draw up toward right (100 half of 200)\n",
" ctx.fill(); // connect and fill\n",
"\n",
" // triangle 3, bottom center\n",
" ctx.beginPath(); // note: w/o this, color does not work as expected \n",
" ctx.fillStyle = \"#F00\";\n",
" ctx.moveTo(300, 200); // pick up \"pen,\" reposition at 300 (horiz), 200 (vert)\n",
" ctx.lineTo(300, 400); // draw straight down by 200px (200 + 200)\n",
" ctx.lineTo(100, 300); // draw up toward left (100 less than 300, so left)\n",
" ctx.fill(); // connect and fill\n",
"\n",
"\n",
"</script>"
],
"text/plain": [
"<__main__.Canvas1 at 0x108b3cf28>"
]
},
"execution_count": 260,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"class Canvas1(object):\n",
" def __init__(self,script,cid='mytag', context=None):\n",
" self.cid=cid\n",
" self.context = context if context else 'ctx'\n",
" self.wrap = context is None\n",
" self._html =[]\n",
" self._add_canvas(cid)\n",
" self._get_canvas()\n",
" self._add_script_tag(script)\n",
" \n",
" def _add_canvas(self, cid):\n",
" html='''<canvas id=\"{}\" width=\"700\" height=\"410\"> <p>Some default content can appear here.</p>\n",
"</canvas>'''.format(cid)\n",
" self._html.append(html)\n",
" \n",
" def _get_canvas(self):\n",
" script = '''<script type=\"text/javascript\">var canvas = document.getElementById('{cid}');\n",
" //if (canvas.getContext) {{}}\n",
" var {ctx} = canvas.getContext('2d');</script> '''.format(cid = self.cid, ctx=self.context)\n",
" self._html.append(script)\n",
" \n",
" def _add_script_tag(self, script):\n",
" if self.wrap:\n",
" self._html.append('<script type=\"text/javascript\">with ({}) {{ {} }}</script>'.format(self.context,script))\n",
" else:\n",
" self._html.append('<script type=\"text/javascript\">{}</script>'.format(script))\n",
"\n",
" def html(self):\n",
" return '\\n'.join(self._html)\n",
" \n",
" def _repr_html_(self):\n",
" return self.html()\n",
"\n",
"\n",
"txt='''\n",
" ctx.beginPath(); // note usage below \n",
"\n",
" // triangle 1, at left\n",
" ctx.fillStyle = \"#F9A520\";\n",
" ctx.moveTo(0, 0); // start at top left corner of canvas\n",
" ctx.lineTo(200, 0); // go 200px to right (x), straight line from 0 to 0\n",
" ctx.lineTo(100, 200); // go to horizontal 100 (x) and vertical 200 (y)\n",
" ctx.fill(); // connect and fill\n",
"\n",
" // triangle 2, top center\n",
" ctx.moveTo(300, 0); // pick up \"pen,\" reposition at 300 (horiz), 0 (vert)\n",
" ctx.lineTo(300, 200); // draw straight down (from 300,0) to 200px\n",
" ctx.lineTo(500, 100); // draw up toward right (100 half of 200)\n",
" ctx.fill(); // connect and fill\n",
"\n",
" // triangle 3, bottom center\n",
" ctx.beginPath(); // note: w/o this, color does not work as expected \n",
" ctx.fillStyle = \"#F00\";\n",
" ctx.moveTo(300, 200); // pick up \"pen,\" reposition at 300 (horiz), 200 (vert)\n",
" ctx.lineTo(300, 400); // draw straight down by 200px (200 + 200)\n",
" ctx.lineTo(100, 300); // draw up toward left (100 less than 300, so left)\n",
" ctx.fill(); // connect and fill\n",
"\n",
"\n",
"'''\n",
"\n",
"txt2='''\n",
" beginPath(); // note usage below \n",
"\n",
" // triangle 1, at left\n",
" fillStyle = \"#F9A520\";\n",
" moveTo(0, 0); // start at top left corner of canvas\n",
" lineTo(200, 0); // go 200px to right (x), straight line from 0 to 0\n",
" lineTo(100, 200); // go to horizontal 100 (x) and vertical 200 (y)\n",
" fill(); // connect and fill\n",
"\n",
" // triangle 3, bottom center\n",
" beginPath(); // note: w/o this, color does not work as expected \n",
" fillStyle = \"#F00\";\n",
" moveTo(300, 200); // pick up \"pen,\" reposition at 300 (horiz), 200 (vert)\n",
" lineTo(300, 400); // draw straight down by 200px (200 + 200)\n",
" lineTo(100, 300); // draw up toward left (100 less than 300, so left)\n",
" fill(); // connect and fill\n",
"\n",
"'''\n",
"Canvas1(txt, context= 'ctx')\n",
"#Canvas1(txt2)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's have a go at creating some magic..."
]
},
{
"cell_type": "code",
"execution_count": 283,
"metadata": {},
"outputs": [],
"source": [
"import random\n",
"import string\n",
"import shlex\n",
"from argparse import ArgumentParser\n",
"from IPython.core.magic import (\n",
" magics_class, line_cell_magic, Magics)\n",
"from IPython.core.display import HTML\n",
"\n",
"@magics_class\n",
"class CanvasMagic(Magics):\n",
" def __init__(self, shell, cache_display_data=False):\n",
" super(CanvasMagic, self).__init__(shell)\n",
" self.cache_display_data = cache_display_data\n",
"\n",
" @line_cell_magic\n",
" def canvas(self,line, cell=''):\n",
" '''Run JS canvas commands.'''\n",
" parser = ArgumentParser()\n",
" parser.add_argument('-c', '--context', default=None)\n",
" parser.add_argument('-I', '--id', default=None)\n",
" parser.add_argument('--wrap', dest='wrap_env', action='store_true')\n",
" parser.add_argument('--no-wrap', dest='wrap_env', action='store_false')\n",
" parser.add_argument('-v', '--variable', default=None)\n",
" parser.set_defaults(wrap_env=False)\n",
" args = parser.parse_args(shlex.split(line))\n",
" \n",
" if args.variable:\n",
" cell = self.shell.user_ns[args.variable]\n",
" \n",
" #Create a random id for the canvas tag to try to prevent clashes\n",
" argsid = args.id if args.id else ''.join(random.choices(string.ascii_uppercase + string.digits, k=5))\n",
" \n",
" if not args.context:\n",
" if not args.wrap_env: context = None\n",
" else: context='ctx'\n",
" else: context = args.context\n",
" #We need to add the extra \\n in case the last line in the cell is a comment that would comment out </script>\n",
" return Canvas1(cell+'\\n', context=context, cid=argsid)"
]
},
{
"cell_type": "code",
"execution_count": 284,
"metadata": {},
"outputs": [],
"source": [
"ip = get_ipython()\n",
"ip.register_magics(CanvasMagic)"
]
},
{
"cell_type": "code",
"execution_count": 285,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<canvas id=\"L49UR\" width=\"700\" height=\"410\"> <p>Some default content can appear here.</p>\n",
"</canvas>\n",
"<script type=\"text/javascript\">var canvas = document.getElementById('L49UR');\n",
" //if (canvas.getContext) {}\n",
" var ctx = canvas.getContext('2d');</script> \n",
"<script type=\"text/javascript\">ctx.beginPath(); \n",
"\n",
"ctx.fillStyle = \"#F9A520\";\n",
"ctx.moveTo(0, 0);\n",
"ctx.lineTo(200, 0); \n",
"ctx.lineTo(100, 200); \n",
"ctx.fill(); \n",
"\n",
"// triangle 2, top center\n",
"ctx.moveTo(300, 0); // pick up \"pen,\" reposition at 300 (horiz), 0 (vert)\n",
"ctx.lineTo(300, 200); // draw straight down (from 300,0) to 200px\n",
"ctx.lineTo(500, 100); // draw up toward right (100 half of 200)\n",
"ctx.fill(); // connect and fill\n",
"\n",
"ctx.stroke(); \n",
"</script>"
],
"text/plain": [
"<__main__.Canvas1 at 0x108b6c0f0>"
]
},
"execution_count": 285,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"%%canvas -c ctx\n",
"ctx.beginPath(); \n",
"\n",
"ctx.fillStyle = \"#F9A520\";\n",
"ctx.moveTo(0, 0);\n",
"ctx.lineTo(200, 0); \n",
"ctx.lineTo(100, 200); \n",
"ctx.fill(); \n",
"\n",
"// triangle 2, top center\n",
"ctx.moveTo(300, 0); // pick up \"pen,\" reposition at 300 (horiz), 0 (vert)\n",
"ctx.lineTo(300, 200); // draw straight down (from 300,0) to 200px\n",
"ctx.lineTo(500, 100); // draw up toward right (100 half of 200)\n",
"ctx.fill(); // connect and fill\n",
"\n",
"ctx.stroke(); "
]
},
{
"cell_type": "code",
"execution_count": 286,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<canvas id=\"0B44E\" width=\"700\" height=\"410\"> <p>Some default content can appear here.</p>\n",
"</canvas>\n",
"<script type=\"text/javascript\">var canvas = document.getElementById('0B44E');\n",
" //if (canvas.getContext) {}\n",
" var ctx = canvas.getContext('2d');</script> \n",
"<script type=\"text/javascript\">with (ctx) { beginPath(); \n",
"\n",
"fillStyle = \"#F9A520\";\n",
"moveTo(0, 0);\n",
"lineTo(200, 0); \n",
"lineTo(100, 200); \n",
"fill(); \n",
"\n",
"beginPath(); \n",
"fillStyle = \"#F00\";\n",
"moveTo(300, 200); \n",
"lineTo(300, 400); // draw straight down by 200px (200 + 200)\n",
"lineTo(100, 300); // draw up toward left (100 less than 300, so left)\n",
"fill(); // connect and fill\n",
" }</script>"
],
"text/plain": [
"<__main__.Canvas1 at 0x108b6c588>"
]
},
"execution_count": 286,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"%%canvas\n",
"beginPath(); \n",
"\n",
"fillStyle = \"#F9A520\";\n",
"moveTo(0, 0);\n",
"lineTo(200, 0); \n",
"lineTo(100, 200); \n",
"fill(); \n",
"\n",
"beginPath(); \n",
"fillStyle = \"#F00\";\n",
"moveTo(300, 200); \n",
"lineTo(300, 400); // draw straight down by 200px (200 + 200)\n",
"lineTo(100, 300); // draw up toward left (100 less than 300, so left)\n",
"fill(); // connect and fill\n"
]
},
{
"cell_type": "code",
"execution_count": 288,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<canvas id=\"1GWNU\" width=\"700\" height=\"410\"> <p>Some default content can appear here.</p>\n",
"</canvas>\n",
"<script type=\"text/javascript\">var canvas = document.getElementById('1GWNU');\n",
" //if (canvas.getContext) {}\n",
" var ctx = canvas.getContext('2d');</script> \n",
"<script type=\"text/javascript\">with (ctx) { \n",
" beginPath(); // note usage below \n",
"\n",
" // triangle 1, at left\n",
" fillStyle = \"#F9A520\";\n",
" moveTo(0, 0); // start at top left corner of canvas\n",
" lineTo(200, 0); // go 200px to right (x), straight line from 0 to 0\n",
" lineTo(100, 200); // go to horizontal 100 (x) and vertical 200 (y)\n",
" fill(); // connect and fill\n",
"\n",
" // triangle 3, bottom center\n",
" beginPath(); // note: w/o this, color does not work as expected \n",
" fillStyle = \"#F00\";\n",
" moveTo(300, 200); // pick up \"pen,\" reposition at 300 (horiz), 200 (vert)\n",
" lineTo(300, 400); // draw straight down by 200px (200 + 200)\n",
" lineTo(100, 300); // draw up toward left (100 less than 300, so left)\n",
" fill(); // connect and fill\n",
"\n",
"\n",
" }</script>"
],
"text/plain": [
"<__main__.Canvas1 at 0x108b72160>"
]
},
"execution_count": 288,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"%canvas -v txt2"
]
},
{
"cell_type": "code",
"execution_count": 289,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<canvas id=\"9A8RO\" width=\"700\" height=\"410\"> <p>Some default content can appear here.</p>\n",
"</canvas>\n",
"<script type=\"text/javascript\">var canvas = document.getElementById('9A8RO');\n",
" //if (canvas.getContext) {}\n",
" var ctx = canvas.getContext('2d');</script> \n",
"<script type=\"text/javascript\">\n",
" ctx.beginPath(); // note usage below \n",
"\n",
" // triangle 1, at left\n",
" ctx.fillStyle = \"#F9A520\";\n",
" ctx.moveTo(0, 0); // start at top left corner of canvas\n",
" ctx.lineTo(200, 0); // go 200px to right (x), straight line from 0 to 0\n",
" ctx.lineTo(100, 200); // go to horizontal 100 (x) and vertical 200 (y)\n",
" ctx.fill(); // connect and fill\n",
"\n",
" // triangle 2, top center\n",
" ctx.moveTo(300, 0); // pick up \"pen,\" reposition at 300 (horiz), 0 (vert)\n",
" ctx.lineTo(300, 200); // draw straight down (from 300,0) to 200px\n",
" ctx.lineTo(500, 100); // draw up toward right (100 half of 200)\n",
" ctx.fill(); // connect and fill\n",
"\n",
" // triangle 3, bottom center\n",
" ctx.beginPath(); // note: w/o this, color does not work as expected \n",
" ctx.fillStyle = \"#F00\";\n",
" ctx.moveTo(300, 200); // pick up \"pen,\" reposition at 300 (horiz), 200 (vert)\n",
" ctx.lineTo(300, 400); // draw straight down by 200px (200 + 200)\n",
" ctx.lineTo(100, 300); // draw up toward left (100 less than 300, so left)\n",
" ctx.fill(); // connect and fill\n",
"\n",
"\n",
"\n",
"</script>"
],
"text/plain": [
"<__main__.Canvas1 at 0x108b6cc88>"
]
},
"execution_count": 289,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"%canvas -v txt --context ctx"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.4"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment