Programmatically generate SVG (vector) images, animations, and interactive Jupyter widgets
1<?xml version="1.0" encoding="UTF-8"?> 2<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" 3 width="400" height="200" viewBox="-200.0 -100.0 400 200" onload="svgOnLoad(event);"> 4<defs> 5</defs> 6<rect x="-200" y="-100" width="400" height="200" fill="#eee" /> 7<circle cx="0" cy="0" r="40" fill="green" /> 8<circle cx="0" cy="0" r="0" fill="gray"> 9<animate attributeName="cx" dur="8s" values="-100;0;100;0;-100" keyTimes="0;0.25;0.5;0.75;1" repeatCount="indefinite" fill="freeze" /> 10<animate attributeName="cy" dur="8s" values="0;-100;0;100;0" keyTimes="0;0.25;0.5;0.75;1" repeatCount="indefinite" fill="freeze" /> 11<animate attributeName="r" dur="8s" values="0;40;0;40;0" keyTimes="0;0.25;0.5;0.75;1" repeatCount="indefinite" fill="freeze" /> 12</circle> 13<rect x="0" y="0" width="0" height="0" fill="silver"> 14<animate attributeName="x" dur="8s" values="-100;-20;100;-20;-100" keyTimes="0;0.25;0.5;0.75;1" repeatCount="indefinite" fill="freeze" /> 15<animate attributeName="y" dur="8s" values="0;-120;0;80;0" keyTimes="0;0.25;0.5;0.75;1" repeatCount="indefinite" fill="freeze" /> 16<animate attributeName="width" dur="8s" values="0;40;0;40;0" keyTimes="0;0.25;0.5;0.75;1" repeatCount="indefinite" fill="freeze" /> 17<animate attributeName="height" dur="8s" values="0;40;0;40;0" keyTimes="0;0.25;0.5;0.75;1" repeatCount="indefinite" fill="freeze" /> 18</rect> 19<text x="0" y="1" font-size="30" fill="yellow" text-anchor="middle" dominant-baseline="central">0<animate attributeName="visibility" dur="8s" values="visible;hidden;hidden" keyTimes="0;0.25;1" repeatCount="indefinite" fill="freeze" /></text> 20<text x="0" y="1" font-size="30" fill="yellow" text-anchor="middle" dominant-baseline="central">1<animate attributeName="visibility" dur="8s" values="hidden;visible;hidden;hidden" keyTimes="0;0.25;0.5;1" repeatCount="indefinite" fill="freeze" /></text> 21<text x="0" y="1" font-size="30" fill="yellow" text-anchor="middle" dominant-baseline="central">2<animate attributeName="visibility" dur="8s" values="hidden;hidden;visible;hidden;hidden" keyTimes="0;0.25;0.5;0.75;1" repeatCount="indefinite" fill="freeze" /></text> 22<text x="0" y="1" font-size="30" fill="yellow" text-anchor="middle" dominant-baseline="central">3<animate attributeName="visibility" dur="8s" values="hidden;hidden;visible;visible" keyTimes="0;0.5;0.75;1" repeatCount="indefinite" fill="freeze" /></text> 23<g id="scrub"> 24<path d="M-168.0,90.0 L168.0,90.0" stroke="#ccc" stroke-width="4" stroke-linecap="round" /> 25<rect x="-168.0" y="90.0" width="0" height="0.001" stroke="#05f" stroke-width="4" stroke-linejoin="round"> 26<animate attributeName="width" dur="8s" values="0;336" keyTimes="0;1" repeatCount="indefinite" fill="freeze" /> 27</rect> 28<g id="scrub-capture" data-xmin="-168.0" data-xmax="168.0" data-totaldur="8" data-startdelay="0" data-enddelay="0" data-pauseonload="0"> 29<rect x="-170.0" y="80.0" width="340" height="20" fill="rgba(255,255,255,0)" /> 30<circle cx="-168.0" cy="90.0" r="6" fill="#05f" id="scrub-knob" visibility="hidden"> 31<animate attributeName="cx" dur="8s" values="-168.0;168.0" keyTimes="0;1" repeatCount="indefinite" fill="freeze" /> 32</circle> 33</g> 34<g id="scrub-play" visibility="hidden"> 35<rect x="-191.0" y="86.0" width="8" height="8" fill="#05f" stroke="#05f" stroke-width="8" stroke-linejoin="round" /> 36<path d="M-191.0,86.0 v8.0 l8.0,-4.0 Z" fill="#eee" /> 37</g> 38<g id="scrub-pause" visibility="hidden"> 39<rect x="-191.0" y="86.0" width="8" height="8" fill="#05f" stroke="#05f" stroke-width="8" stroke-linejoin="round" /> 40<rect x="-190.0" y="86.0" width="2.0" height="8.0" fill="#eee" /> 41<rect x="-186.0" y="86.0" width="2.0" height="8.0" fill="#eee" /> 42</g> 43</g> 44<script>/*<![CDATA[*/ 45/* Animation playback controls generated by drawsvg */ 46/* https://github.com/cduck/drawsvg/ */ 47function svgOnLoad(event) { 48 /* Support standalone SVG or embedded in HTML or iframe */ 49 if (event && event.target && event.target.ownerDocument) { 50 svgSetup(event.target.ownerDocument); 51 } else if (document && document.currentScript 52 && document.currentScript.parentElement) { 53 svgSetup(document.currentScript.parentElement); 54 } 55} 56function svgSetup(doc) { 57 var svgRoot = doc.documentElement || doc; 58 var scrubCapture = doc.getElementById("scrub-capture"); 59 /* Block multiple setups */ 60 if (!scrubCapture || scrubCapture.getAttribute("svgSetupDone")) { 61 return; 62 } 63 scrubCapture.setAttribute("svgSetupDone", true); 64 var scrubContainer = doc.getElementById("scrub"); 65 var scrubPlay = doc.getElementById("scrub-play"); 66 var scrubPause = doc.getElementById("scrub-pause"); 67 var scrubKnob = doc.getElementById("scrub-knob"); 68 var scrubXMin = parseFloat(scrubCapture.dataset.xmin); 69 var scrubXMax = parseFloat(scrubCapture.dataset.xmax); 70 var scrubTotalDur = parseFloat(scrubCapture.dataset.totaldur); 71 var scrubStartDelay = parseFloat(scrubCapture.dataset.startdelay); 72 var scrubEndDelay = parseFloat(scrubCapture.dataset.enddelay); 73 var scrubPauseOnLoad = parseFloat(scrubCapture.dataset.pauseonload); 74 var paused = false; 75 var dragXOffset = 0; 76 var point = svgRoot.createSVGPoint(); 77 78 function screenToSvgX(p) { 79 var matrix = scrubKnob.getScreenCTM().inverse(); 80 point.x = p.x; 81 point.y = p.y; 82 return point.matrixTransform(matrix).x; 83 }; 84 function screenToProgress(p) { 85 var matrix = scrubKnob.getScreenCTM().inverse(); 86 point.x = p.x; 87 point.y = p.y; 88 var x = point.matrixTransform(matrix).x; 89 if (x <= scrubXMin) { 90 return scrubStartDelay / scrubTotalDur; 91 } 92 if (x >= scrubXMax) { 93 return (scrubTotalDur - scrubEndDelay) / scrubTotalDur; 94 } 95 return (scrubStartDelay/scrubTotalDur 96 + (x - dragXOffset - scrubXMin) 97 / (scrubXMax - scrubXMin) 98 * (scrubTotalDur - scrubStartDelay - scrubEndDelay) 99 / scrubTotalDur); 100 }; 101 function currentScrubX() { 102 return scrubKnob.cx.animVal.value; 103 }; 104 function pause() { 105 svgRoot.pauseAnimations(); 106 scrubPlay.setAttribute("visibility", "visible"); 107 scrubPause.setAttribute("visibility", "hidden"); 108 paused = true; 109 }; 110 function play() { 111 svgRoot.unpauseAnimations(); 112 scrubPause.setAttribute("visibility", "visible"); 113 scrubPlay.setAttribute("visibility", "hidden"); 114 paused = false; 115 }; 116 function scrub(playbackFraction) { 117 var t = scrubTotalDur * playbackFraction; 118 /* Stop 10ms before end to avoid loop (>=1ms needed on FF) */ 119 var limit = scrubTotalDur - 10e-3; 120 if (t < 0) t = 0; 121 else if (t > limit) t = limit; 122 svgRoot.setCurrentTime(t); 123 }; 124 function mousedown(e) { 125 svgRoot.pauseAnimations(); 126 if (e.target == scrubKnob) { 127 dragXOffset = screenToSvgX(e) - currentScrubX(); 128 } else { 129 dragXOffset = 0; 130 } 131 scrub(screenToProgress(e)); 132 /* Global document listeners */ 133 document.addEventListener('mousemove', mousemove); 134 document.addEventListener('mouseup', mouseup); 135 e.preventDefault(); 136 }; 137 function mouseup(e) { 138 dragXOffset = 0; 139 document.removeEventListener('mousemove', mousemove); 140 document.removeEventListener('mouseup', mouseup); 141 if (!paused) { 142 svgRoot.unpauseAnimations(); 143 } 144 e.preventDefault(); 145 }; 146 function mousemove(e) { 147 scrub(screenToProgress(e)); 148 }; 149 scrubPause.addEventListener("click", pause); 150 scrubPlay.addEventListener("click", play); 151 scrubCapture.addEventListener("mousedown", mousedown); 152 scrubContainer.setAttribute("visibility", "visible"); 153 scrubKnob.setAttribute("visibility", "visible"); 154 if (scrubPauseOnLoad) { 155 pause(); 156 scrub(0); 157 } else { 158 play(); 159 } 160}; 161svgOnLoad(); 162/*]]>*/</script> 163</svg>