<\/p>\r\n
<\/p>\r\n <\/div>","numboards":2,"description":"Visualize complex function $w = f(z)$. Draw a curve with the mouse in the left panel (the domain) and its image under $f$ appears on the right.\r\n\r\nHeavily influenced by [an app by Terence Tao](https:\/\/teorth.github.io\/tao-web\/apps\/elementary-complex-maps.html).","dimensions":[{"width":"50%","height":null,"aspect-ratio":"1 \/ 1"},{"width":"50%","height":null,"aspect-ratio":"1 \/ 1"}],"wider":0,"license":{"id":2,"identifier":"CC BY-SA 4.0","title":"Creative Commons Attribution ShareAlike 4.0 International","free":"- Share\r\n- Adapt","restrictions":"- Attribution\r\n- ShareAlike\r\n- No additional restrictions","with_attribution":1,"link":"https:\/\/creativecommons.org\/licenses\/by-sa\/4.0\/","image":"https:\/\/i.creativecommons.org\/l\/by-sa\/4.0\/88x31.png","rank":1},"timestamp":"2026-07-21 11:58:12","visible":1,"tags":[{"id":106,"alias":"calculus","name":"Calculus"},{"id":110,"alias":"function-plotting","name":"Function plotting"},{"id":159,"alias":"sketch","name":"sketch"}],"tag_ids":[106,110,159],"refers_to":[{"id":10296,"alias":"sketchcurve-element","name":"Sketching with the sketchcurve element","symmetrical":1}],"refers_to_ids":[10296],"authors":[],"authors_ids":[],"unique_ids":["jxgbox-6a5ff50233bc2","jxgbox-6a5ff50233bc3"],"code_display":"\/\/ Define the ids of your boards in BOARDID0, BOARDID1,...\n\n const board = JXG.JSXGraph.initBoard(BOARDID0, {\r\n boundingbox: [-10, 10, 10, -10],\r\n keepaspectratio: false,\r\n axis: true,\r\n pan: { enabled: false },\r\n sketches: {\r\n enabled: true,\r\n 0: { visible: true },\r\n 1: { visible: true, strokeColor: JXG.palette.blue }\r\n }\r\n });\r\n var board2 = JXG.JSXGraph.initBoard(BOARDID1, {\r\n boundingbox: [-10, 10, 10, -10],\r\n keepaspectratio: false,\r\n axis: true,\r\n pan: { enabled: false },\r\n sketches: {\r\n enabled: true,\r\n 0: { visible: true, strokeColor: JXG.palette.blue, strokeWidth: 3 }\r\n }\r\n });\r\n board.addChild(board2);\r\n\r\n var funcs = {\r\n 'z': (z) => z,\r\n 'z + i': (z) => {\r\n let i = new JXG.Complex(0, 1);\r\n return i.add(z);\r\n },\r\n '2z': (z) => {\r\n let w = new JXG.Complex(2, 0);\r\n return w.mult(z);\r\n },\r\n '-z': (z) => {\r\n let w = new JXG.Complex(-1, 0);\r\n return w.mult(z);\r\n },\r\n 'iz': (z) => {\r\n let w = new JXG.Complex(0, 1);\r\n return w.mult(z);\r\n },\r\n '(1+i)z': (z) => {\r\n let w = new JXG.Complex(1, 1);\r\n return w.mult(z);\r\n },\r\n 'conj(z)': (z) => {\r\n return JXG.C.conj(z);\r\n },\r\n '9\/conj(z)': (z) => {\r\n let w = new JXG.Complex(9, 0);\r\n return JXG.C.div(w, JXG.C.conj(z));\r\n },\r\n 'Re(z)': (z) => {\r\n return new JXG.Complex(z.real, 0);\r\n },\r\n 'i Im(z)': (z) => {\r\n return new JXG.Complex(0, z.imaginary);\r\n },\r\n 'x+2iy': (z) => {\r\n return new JXG.Complex(z.real, 2 * z.imaginary);\r\n },\r\n 'z^2': (z) => {\r\n return z.mult(z);\r\n },\r\n 'z^3': (z) => {\r\n let res = z.mult(z);\r\n return res.mult(z);\r\n },\r\n '1\/z': (z) => {\r\n let one = new JXG.Complex(1, 1);\r\n return one.div(z);\r\n },\r\n 'e^z': (z) => {\r\n let re = z.real,\r\n im = z.imaginary,\r\n s = Math.exp(re);\r\n return new JXG.Complex(s * Math.cos(im), s * Math.sin(im));\r\n }\r\n };\r\n var f = funcs['z'];\r\n\r\n setTimeout(function() {\r\n document.getElementById('functionterms').addEventListener('change', function(evt) {\r\n f = funcs[evt.target.value];\r\n });\r\n }, 500);\r\n\r\n var arr1 = board.create('arrow', [[0, 0], [0, 0]], { highlight: false, fixed: true });\r\n var arr2 = board2.create('arrow', [[0, 0], [0, 0]], { highlight: false, fixed: true });\r\n\r\n var map_curvepoint = function(pos) {\r\n var z, w;\r\n\r\n \/\/ We just have to care about the mapped data point.\r\n \/\/ The data point is handled by board.sketch automatically.\r\n z = new JXG.Complex(pos[0], pos[1]);\r\n w = f(z);\r\n\r\n \/\/ Regardless if mouse key pressed or not, write the coordinates and position the arrows.\r\n\r\n \/\/ Write coordinates of z and f(z)\r\n out_z.innerHTML = `z = ${z.toString(4)}`;\r\n out_fz.innerHTML = `f(z) = ${w.toString(4)}`;\r\n\r\n \/\/ Position the arrows\r\n arr1.point2.moveTo([z.real, z.imaginary]);\r\n arr2.point2.moveTo([w.real, w.imaginary]);\r\n\r\n \/\/ Only if mouse key pressed do sketching\r\n if (board.isSketching[0]) {\r\n board2.sketch.dataX.push(w.real);\r\n board2.sketch.dataY.push(w.imaginary);\r\n }\r\n };\r\n\r\n \/\/ On down in the left board, delete the curve in the right board.\r\n board.on('down', function(evt) {\r\n \/\/ Reset map curve\r\n board2.sketch.dataX = [];\r\n board2.sketch.dataY = [];\r\n\r\n \/\/ Grab the last actual mouse position and map it \r\n map_curvepoint(this.getUsrCoordsOfMouse(evt));\r\n });\r\n\r\n board.on('move', function(evt, mode) {\r\n \/\/ Grab the last actual mouse position and map it \r\n map_curvepoint(this.getUsrCoordsOfMouse(evt));\r\n });","code_execute_html":"
<iframe src="https://jsxgraph.uni-bayreuth.de/share/iframe/complex-maps" style="border: 1px solid black; overflow: hidden; width: 550px; aspect-ratio: 55 / 65;" name="JSXGraph example: Complex maps" allowfullscreen ></iframe>
<select id="functionterms" style="max-width:300px"> <option>z</option> <option>z + i</option> <option>2z</option> <option>-z</option> <option>iz</option> <option>(1+i)z</option> <option>conj(z)</option> <option>9/conj(z)</option> <option>Re(z)</option> <option>i Im(z)</option> <option>x+2iy</option> <option>z^2</option> <option>z^3</option> <option>1/z</option> <option>e^z</option> </select> <div id="board-0-wrapper" class="jxgbox-wrapper " style="width: 100%; "> <div id="board-0" class="jxgbox" style="aspect-ratio: 1 / 1; width: 50%;" data-ar="1 / 1"></div> </div> <div id="board-1-wrapper" class="jxgbox-wrapper " style="width: 100%; "> <div id="board-1" class="jxgbox" style="aspect-ratio: 1 / 1; width: 50%;" data-ar="1 / 1"></div> </div> <div style="width: 600px; display:grid; border: 1px black solid; grid-template-columns: 1fr 1fr; max-width: 100%; padding: 20px;"> <p id="out_z" style="max-width:200px;"></p> <p id="out_fz" style="max-width:200px;"></p> </div> <script type = "text/javascript"> /* This example is licensed under a Creative Commons Attribution ShareAlike 4.0 International License. https://creativecommons.org/licenses/by-sa/4.0/ Please note you have to mention The Center of Mobile Learning with Digital Technology in the credits. */ const BOARDID0 = 'board-0'; const BOARDID1 = 'board-1'; const BOARDID = BOARDID0; const board = JXG.JSXGraph.initBoard(BOARDID0, { boundingbox: [-10, 10, 10, -10], keepaspectratio: false, axis: true, pan: { enabled: false }, sketches: { enabled: true, 0: { visible: true }, 1: { visible: true, strokeColor: JXG.palette.blue } } }); var board2 = JXG.JSXGraph.initBoard(BOARDID1, { boundingbox: [-10, 10, 10, -10], keepaspectratio: false, axis: true, pan: { enabled: false }, sketches: { enabled: true, 0: { visible: true, strokeColor: JXG.palette.blue, strokeWidth: 3 } } }); board.addChild(board2); var funcs = { 'z': (z) => z, 'z + i': (z) => { let i = new JXG.Complex(0, 1); return i.add(z); }, '2z': (z) => { let w = new JXG.Complex(2, 0); return w.mult(z); }, '-z': (z) => { let w = new JXG.Complex(-1, 0); return w.mult(z); }, 'iz': (z) => { let w = new JXG.Complex(0, 1); return w.mult(z); }, '(1+i)z': (z) => { let w = new JXG.Complex(1, 1); return w.mult(z); }, 'conj(z)': (z) => { return JXG.C.conj(z); }, '9/conj(z)': (z) => { let w = new JXG.Complex(9, 0); return JXG.C.div(w, JXG.C.conj(z)); }, 'Re(z)': (z) => { return new JXG.Complex(z.real, 0); }, 'i Im(z)': (z) => { return new JXG.Complex(0, z.imaginary); }, 'x+2iy': (z) => { return new JXG.Complex(z.real, 2 * z.imaginary); }, 'z^2': (z) => { return z.mult(z); }, 'z^3': (z) => { let res = z.mult(z); return res.mult(z); }, '1/z': (z) => { let one = new JXG.Complex(1, 1); return one.div(z); }, 'e^z': (z) => { let re = z.real, im = z.imaginary, s = Math.exp(re); return new JXG.Complex(s * Math.cos(im), s * Math.sin(im)); } }; var f = funcs['z']; setTimeout(function() { document.getElementById('functionterms').addEventListener('change', function(evt) { f = funcs[evt.target.value]; }); }, 500); var arr1 = board.create('arrow', [[0, 0], [0, 0]], { highlight: false, fixed: true }); var arr2 = board2.create('arrow', [[0, 0], [0, 0]], { highlight: false, fixed: true }); var map_curvepoint = function(pos) { var z, w; // We just have to care about the mapped data point. // The data point is handled by board.sketch automatically. z = new JXG.Complex(pos[0], pos[1]); w = f(z); // Regardless if mouse key pressed or not, write the coordinates and position the arrows. // Write coordinates of z and f(z) out_z.innerHTML = `z = ${z.toString(4)}`; out_fz.innerHTML = `f(z) = ${w.toString(4)}`; // Position the arrows arr1.point2.moveTo([z.real, z.imaginary]); arr2.point2.moveTo([w.real, w.imaginary]); // Only if mouse key pressed do sketching if (board.isSketching[0]) { board2.sketch.dataX.push(w.real); board2.sketch.dataY.push(w.imaginary); } }; // On down in the left board, delete the curve in the right board. board.on('down', function(evt) { // Reset map curve board2.sketch.dataX = []; board2.sketch.dataY = []; // Grab the last actual mouse position and map it map_curvepoint(this.getUsrCoordsOfMouse(evt)); }); board.on('move', function(evt, mode) { // Grab the last actual mouse position and map it map_curvepoint(this.getUsrCoordsOfMouse(evt)); }); </script>
/* This example is licensed under a Creative Commons Attribution ShareAlike 4.0 International License. https://creativecommons.org/licenses/by-sa/4.0/ Please note you have to mention The Center of Mobile Learning with Digital Technology in the credits. */ const BOARDID0 = 'your_div_id_0'; // Insert your 1st board id here! const BOARDID1 = 'your_div_id_1'; // Insert your 2nd board id here! const board = JXG.JSXGraph.initBoard(BOARDID0, { boundingbox: [-10, 10, 10, -10], keepaspectratio: false, axis: true, pan: { enabled: false }, sketches: { enabled: true, 0: { visible: true }, 1: { visible: true, strokeColor: JXG.palette.blue } } }); var board2 = JXG.JSXGraph.initBoard(BOARDID1, { boundingbox: [-10, 10, 10, -10], keepaspectratio: false, axis: true, pan: { enabled: false }, sketches: { enabled: true, 0: { visible: true, strokeColor: JXG.palette.blue, strokeWidth: 3 } } }); board.addChild(board2); var funcs = { 'z': (z) => z, 'z + i': (z) => { let i = new JXG.Complex(0, 1); return i.add(z); }, '2z': (z) => { let w = new JXG.Complex(2, 0); return w.mult(z); }, '-z': (z) => { let w = new JXG.Complex(-1, 0); return w.mult(z); }, 'iz': (z) => { let w = new JXG.Complex(0, 1); return w.mult(z); }, '(1+i)z': (z) => { let w = new JXG.Complex(1, 1); return w.mult(z); }, 'conj(z)': (z) => { return JXG.C.conj(z); }, '9/conj(z)': (z) => { let w = new JXG.Complex(9, 0); return JXG.C.div(w, JXG.C.conj(z)); }, 'Re(z)': (z) => { return new JXG.Complex(z.real, 0); }, 'i Im(z)': (z) => { return new JXG.Complex(0, z.imaginary); }, 'x+2iy': (z) => { return new JXG.Complex(z.real, 2 * z.imaginary); }, 'z^2': (z) => { return z.mult(z); }, 'z^3': (z) => { let res = z.mult(z); return res.mult(z); }, '1/z': (z) => { let one = new JXG.Complex(1, 1); return one.div(z); }, 'e^z': (z) => { let re = z.real, im = z.imaginary, s = Math.exp(re); return new JXG.Complex(s * Math.cos(im), s * Math.sin(im)); } }; var f = funcs['z']; setTimeout(function() { document.getElementById('functionterms').addEventListener('change', function(evt) { f = funcs[evt.target.value]; }); }, 500); var arr1 = board.create('arrow', [[0, 0], [0, 0]], { highlight: false, fixed: true }); var arr2 = board2.create('arrow', [[0, 0], [0, 0]], { highlight: false, fixed: true }); var map_curvepoint = function(pos) { var z, w; // We just have to care about the mapped data point. // The data point is handled by board.sketch automatically. z = new JXG.Complex(pos[0], pos[1]); w = f(z); // Regardless if mouse key pressed or not, write the coordinates and position the arrows. // Write coordinates of z and f(z) out_z.innerHTML = `z = ${z.toString(4)}`; out_fz.innerHTML = `f(z) = ${w.toString(4)}`; // Position the arrows arr1.point2.moveTo([z.real, z.imaginary]); arr2.point2.moveTo([w.real, w.imaginary]); // Only if mouse key pressed do sketching if (board.isSketching[0]) { board2.sketch.dataX.push(w.real); board2.sketch.dataY.push(w.imaginary); } }; // On down in the left board, delete the curve in the right board. board.on('down', function(evt) { // Reset map curve board2.sketch.dataX = []; board2.sketch.dataY = []; // Grab the last actual mouse position and map it map_curvepoint(this.getUsrCoordsOfMouse(evt)); }); board.on('move', function(evt, mode) { // Grab the last actual mouse position and map it map_curvepoint(this.getUsrCoordsOfMouse(evt)); });
<select id="functionterms" style="max-width:300px"> <option>z</option> <option>z + i</option> <option>2z</option> <option>-z</option> <option>iz</option> <option>(1+i)z</option> <option>conj(z)</option> <option>9/conj(z)</option> <option>Re(z)</option> <option>i Im(z)</option> <option>x+2iy</option> <option>z^2</option> <option>z^3</option> <option>1/z</option> <option>e^z</option> </select>
// Define the ids of your boards in BOARDID0, BOARDID1,... const board = JXG.JSXGraph.initBoard(BOARDID0, { boundingbox: [-10, 10, 10, -10], keepaspectratio: false, axis: true, pan: { enabled: false }, sketches: { enabled: true, 0: { visible: true }, 1: { visible: true, strokeColor: JXG.palette.blue } } }); var board2 = JXG.JSXGraph.initBoard(BOARDID1, { boundingbox: [-10, 10, 10, -10], keepaspectratio: false, axis: true, pan: { enabled: false }, sketches: { enabled: true, 0: { visible: true, strokeColor: JXG.palette.blue, strokeWidth: 3 } } }); board.addChild(board2); var funcs = { 'z': (z) => z, 'z + i': (z) => { let i = new JXG.Complex(0, 1); return i.add(z); }, '2z': (z) => { let w = new JXG.Complex(2, 0); return w.mult(z); }, '-z': (z) => { let w = new JXG.Complex(-1, 0); return w.mult(z); }, 'iz': (z) => { let w = new JXG.Complex(0, 1); return w.mult(z); }, '(1+i)z': (z) => { let w = new JXG.Complex(1, 1); return w.mult(z); }, 'conj(z)': (z) => { return JXG.C.conj(z); }, '9/conj(z)': (z) => { let w = new JXG.Complex(9, 0); return JXG.C.div(w, JXG.C.conj(z)); }, 'Re(z)': (z) => { return new JXG.Complex(z.real, 0); }, 'i Im(z)': (z) => { return new JXG.Complex(0, z.imaginary); }, 'x+2iy': (z) => { return new JXG.Complex(z.real, 2 * z.imaginary); }, 'z^2': (z) => { return z.mult(z); }, 'z^3': (z) => { let res = z.mult(z); return res.mult(z); }, '1/z': (z) => { let one = new JXG.Complex(1, 1); return one.div(z); }, 'e^z': (z) => { let re = z.real, im = z.imaginary, s = Math.exp(re); return new JXG.Complex(s * Math.cos(im), s * Math.sin(im)); } }; var f = funcs['z']; setTimeout(function() { document.getElementById('functionterms').addEventListener('change', function(evt) { f = funcs[evt.target.value]; }); }, 500); var arr1 = board.create('arrow', [[0, 0], [0, 0]], { highlight: false, fixed: true }); var arr2 = board2.create('arrow', [[0, 0], [0, 0]], { highlight: false, fixed: true }); var map_curvepoint = function(pos) { var z, w; // We just have to care about the mapped data point. // The data point is handled by board.sketch automatically. z = new JXG.Complex(pos[0], pos[1]); w = f(z); // Regardless if mouse key pressed or not, write the coordinates and position the arrows. // Write coordinates of z and f(z) out_z.innerHTML = `z = ${z.toString(4)}`; out_fz.innerHTML = `f(z) = ${w.toString(4)}`; // Position the arrows arr1.point2.moveTo([z.real, z.imaginary]); arr2.point2.moveTo([w.real, w.imaginary]); // Only if mouse key pressed do sketching if (board.isSketching[0]) { board2.sketch.dataX.push(w.real); board2.sketch.dataY.push(w.imaginary); } }; // On down in the left board, delete the curve in the right board. board.on('down', function(evt) { // Reset map curve board2.sketch.dataX = []; board2.sketch.dataY = []; // Grab the last actual mouse position and map it map_curvepoint(this.getUsrCoordsOfMouse(evt)); }); board.on('move', function(evt, mode) { // Grab the last actual mouse position and map it map_curvepoint(this.getUsrCoordsOfMouse(evt)); });
<div style="width: 600px; display:grid; border: 1px black solid; grid-template-columns: 1fr 1fr; max-width: 100%; padding: 20px;"> <p id="out_z" style="max-width:200px;"></p> <p id="out_fz" style="max-width:200px;"></p> </div>
This example is licensed under a Creative Commons Attribution ShareAlike 4.0 International License. Please note you have to mention The Center of Mobile Learning with Digital Technology in the credits.