I was inspired by the first person to port the SVG Doge to Khan Academy (the link might be to a clone and not the original). I deduced from the highly detailed image that it must have initially been an SVG file because it’s essentially impossible to create it using just the Khan Academy environment. Creating such a detailed image necessitates the use of vector editing software like Illustrator and Inkscape. Also, the decimal precise coordinates were a giveaway that it was imported from somewhere.
I Googled around for a copy of the Doge SVG file, and came across this one shared on Reddit.
After messing around for a bit, I was able to port a portion of it to Khan Academy.
I was not aware that this was a possibility! This is exciting because it means you can use dedicated software like Illustrator and Inkscape to generate rich images, and then use said images in HTML5 Canvas.
How to Port
A typical SVG
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="200px" height="164px" viewBox="0 65.326 612 502.174"
enable-background="new 0 65.326 612 502.174" xml:space="preserve"
class="logo">
<ellipse fill="#787f6a" class="ground" cx="283.5" cy="487.5" rx="259" ry="80"/>
<path fill="#94d31b" class="kiwi"
d="M210.333,65.331
C104.367,66.105-12.349,150.637,1.056,276.449
c4.303,40.393,18.533,63.704,52.171,79.03
c36.307,16.544,57.022,54.556,50.406,112.954
c-9.935,4.88-17.405,11.031-19.132,20.015
c7.531-0.17,14.943-0.312,22.59,4.341
c20.333,12.375,31.296,27.363,42.979,51.72
c1.714,3.572,8.192,2.849,8.312-3.078
c0.17-8.467-1.856-17.454-5.226-26.933
c-2.955-8.313,3.059-7.985,6.917-6.106
c6.399,3.115,16.334,9.43,30.39,13.098
c5.392,1.407,5.995-3.877,5.224-6.991
c-1.864-7.522-11.009-10.862-24.519-19.229
c-4.82-2.984-0.927-9.736,5.168-8.351l20.234,2.415
c3.359,0.763,4.555-6.114,0.882-7.875
c-14.198-6.804-28.897-10.098-53.864-7.799
c-11.617-29.265-29.811-61.617-15.674-81.681
c12.639-17.938,31.216-20.74,39.147,43.489
c-5.002,3.107-11.215,5.031-11.332,13.024
c7.201-2.845,11.207-1.399,14.791,0
c17.912,6.998,35.462,21.826,52.982,37.309
c3.739,3.303,8.413-1.718,6.991-6.034
c-2.138-6.494-8.053-10.659-14.791-20.016
c-3.239-4.495,5.03-7.045,10.886-6.876
c13.849,0.396,22.886,8.268,35.177,11.218
c4.483,1.076,9.741-1.964,6.917-6.917
c-3.472-6.085-13.015-9.124-19.18-13.413
c-4.357-3.029-3.025-7.132,2.697-6.602
c3.905,0.361,8.478,2.271,13.908,1.767
c9.946-0.925,7.717-7.169-0.883-9.566
c-19.036-5.304-39.891-6.311-61.665-5.225
c-43.837-8.358-31.554-84.887,0-90.363
c29.571-5.132,62.966-13.339,99.928-32.156
c32.668-5.429,64.835-12.446,92.939-33.85
c48.106-14.469,111.903,16.113,204.241,149.695
c3.926,5.681,15.819,9.94,9.524-6.351
c-15.893-41.125-68.176-93.328-92.13-132.085
c-24.581-39.774-14.34-61.243-39.957-91.247
c-21.326-24.978-47.502-25.803-77.339-17.365
c-23.461,6.634-39.234-7.117-52.98-31.273
C318.42,87.525,265.838,64.927,210.333,65.331
z M445.731,203.01
c6.12,0,11.112,4.919,11.112,11.038
c0,6.119-4.994,11.111-11.112,11.111
s-11.038-4.994-11.038-11.111
C434.693,207.929,439.613,203.01,445.731,203.01z"/>
</svg>
The bird SVG and its code is from here. This particular drawing is simple so all it’s code can fit in a few of lines. The Doge SVG is a much larger file. Below, we will be looking at one tiny part of it, the eyeshadow.
Doge's SVG code
The Doge’s eyeshadow,
M 1221.521, 790
c -20.16, 3.92, -49.334, 24, -64.668, 35.333
c -15.332, 11.333, -25.332, 18.667, -44, 28
c -18.666, 9.333, -42.666, 29.333, -48.666, 34.667
s -0.668, 25.333, 18.666, 38
s 9.334, 26, 23.334, 32
s 24, 7.333, 58.666, 16
c 34.668, 8.667, 56, 13.333, 81.334, 11.333
s 32.666, -3.334, 54.666, -18.667
s 32.668, -32, 44.668, -40.667
s 24, -19.333, 24.666, -32.667
c 0.666, -13.333, -14, -24.667, -36.666, -48.667
c -22.668, -24, -44, -46, -65.334, -52
C 1246.854, 786.667, 1245.521, 785.333, 1221.521, 790
M - move to
c - relative curve to (equivalent of bezierVertex(cx1,cy1,cx2,cy2,x2,y2)
)
s - relative smooth curve to (not sure what this is, but see below for how to convert to c)
C - absolute curve to (equivalent of bezierVertex(cx1,cy1,cx2,cy2,x2,y2)
)
From relative to absolute coordinates
The first step is to convert the relative coordinates in the SVG to absolute coordinates.
For example this,
M 1221.521, 790
c -20.16, 3.92, -49.334, 24, -64.668, 35.333
becomes this,
Vertex( 1221.521, 790 );
bezierVertex(1201.361, 793.92, 1172.187, 814, 1156.853, 825.333);
Notice how each of the points is calculated as (1221.521 + pt.x, 790 + pt.y)
i.e. each of the points is relative to (1221.521, 790)
The catch - the reference point for the next bezier is not (1221.521, 790)
. It is now (1156.853, 825.333)
this,
//M 1156.853, 825.333 //this line implied, so not generated by svg
c -15.332, 11.333, -25.332, 18.667, -44, 28
becomes this,
//Vertex(1156.853, 825.333); //redundant line, but illustrates concept
bezierVertex(1141.521, 836.666, 1131.521, 844.0, 1112.853, 853.333);
Notice how each of the points is calculated as (1156.853 + pt.x, 825.333 + pt.y)
Smooth to regular
The second step is to convert the 2 point s-curves to 3 point c-curves. The equation below comes from this StackOverflow answer.
M X0, Y0
C X1, Y1, X2, Y2, X3, Y3
S X4, Y4, X5, Y5
M X0, Y0
C X1, Y1, X2, Y2, X3, Y3
C XR, YR, X4, Y4, X5, Y5
XR = 2*X3 - X2
YR = 2*Y3 - Y2
All together
The Doge’s eyeshadow SVG code becomes this JavaScript code,
fill(142, 92, 39);
var eyeshadow = function(){
beginShape();
vertex(1221.521, 790);
bezierVertex(1201.361, 793.92, 1172.187, 814, 1156.853, 825.333);
bezierVertex(1141.521, 836.666, 1131.521, 844.0, 1112.853, 853.333);
bezierVertex(1094.187, 862.666, 1070.187, 882.666, 1064.187, 888.0);
bezierVertex(1058.187, 893.33, 1063.519, 913.333, 1082.853, 926.0);
bezierVertex(1102.183, 938.67, 1092.187, 952.0, 1106.187, 958.0);
bezierVertex(1120.187, 964.0, 1130.187, 965.333, 1164.853, 974.0);
bezierVertex(1199.521, 982.667, 1220.853, 987.333, 1246.187, 985.333);
bezierVertex(1271.517, 983.333, 1278.853, 981.999, 1300.853, 966.666);
bezierVertex(1322.853, 951.336, 1333.521, 934.666, 1345.521, 925.999);
bezierVertex(1357.521, 917.329, 1369.521, 906.666, 1370.187, 893.332);
bezierVertex(1370.853, 879.999, 1356.187, 868.665, 1333.521, 844.665);
bezierVertex(1310.853, 820.665, 1289.521, 798.665, 1268.187, 792.665);
bezierVertex(1246.854, 786.667, 1245.521, 785.333, 1221.521, 790);
endShape(CLOSE);
};
eyeshadow();
Scaling
Since there can be several bezier curves in a drawing, writing a script to do these calculations is essential for your sanity.
The script needs to convert the relative points to absolute points. It also needs to convert the 2 point s-curves to 3 point bezier-curves.
Good luck!
References