title: SVG and Canvas read SVG data differently
body: <p>I am attempting to write some JS which uses Canvas to emulate how SVG draws a shape on an image but I can't seem to get it to work. </p>
  
  <p>I have some SVG data which draws a mouth on a face.</p>
  
  <pre><code>&lt;svg id="svgTag" style="background: url('https://image.ibb.co/h9CWiR/odd_size.png') no-repeat " xmlns="http://www.w3.org/2000/svg" version="1.0" width="379.000000" height="540.000000" viewBox="0 0 379.000000 540.000000" preserveAspectRatio="xMidYMid meet"&gt;
      &lt;g transform="translate(0.000000,540.0000) scale(1.000000,-1.000000)" fill="#000000" stroke="none"&gt;
          &lt;path d="M172 147
                 c-21 -1 -69 -8 -74 -10
                 l-2 -1 0 -32 0 -33 3 -4
                 c9 -14 31 -36 44 -45
                 12 -9 16 -11 27 -13
                 2 -1 8 -2 12 -2
                 9 -2 33 -3 34 -1
                 0 1 1 1 2 1
                 2 0 6 1 9 2
                 16 5 29 14 47 32
                 l9 8 0 44
                 c0 33 0 43 -1 44 -4 3 -31 8 -49 10 -14 1 -44 1 -61 0
                 z"/&gt;
      &lt;/g&gt;
  &lt;/svg&gt;
  </code></pre>
  
  <p>I have a fiddle of this here: <a href="https://jsfiddle.net/nhoughto5/5dhn1nm1/" rel="nofollow noreferrer">https://jsfiddle.net/nhoughto5/5dhn1nm1/</a></p>
  
  <p>I have written some javascript which takes the path data from the SVG element, parses it then uses Canvas methods to draw the same mouth. I've implemented a recursive solution to step through each command and draw it in exactly the same way. </p>
  
  <pre><code> const commandString = /[\-0-9,. ]+/ig;
    const commandPattern = /[A-z]+/ig;
    const stringSplit = /[, ]+/ig;
    const shiftX = 0, shiftY = 0;
  
    function cleanArray(array) {
      const tmpArray = [];
      for (let i = 0; i &lt; array.length; i++) {
        if (array[i].length &gt; 0) {
          tmpArray.push(parseInt(array[i]));
        }
      }
      return tmpArray;
    }
    function move(array, context) {
      let x = array[0];
      let y = array[1];
      context.moveTo(x + shiftX, y + shiftY);
      //context.fill();
    }
  
    function quadraticTo(array, context) {
      let x = array[0];
      let y = array[1];
      let x1 = array[2];
      let y1 = array[3];
      context.quadraticCurveTo(x + shiftX, y + shiftY, x1 + shiftX, y1 + shiftY);
      context.fill();
      if (array.length &gt; 4) {
        quadraticTo(array.splice(4, array.length), context);
      }
    }
  
    function lineTo(array, context) {
      let x = array[0];
      let y = array[1];
      context.lineTo(x + shiftX, y + shiftY);
      context.fill();
      if (array.length &gt; 2) {
        lineTo(array.splice(2, array.length), context);
      }
    }
  
    function curveTo(array, context) {
      let x = array[0];
      let y = array[1];
      let x1 = array[2];
      let y1 = array[3];
      let x2 = array[4];
      let y2 = array[5];
      context.bezierCurveTo(x + shiftX, y + shiftY, x1 + shiftX, y1 + shiftY, x2 + shiftX, y2 + shiftY);
      context.fill();
      if (array.length &gt; 6) {
        this._curveTo(array.splice(6, array.length), context);
      }
    }
    function draw(path, context){
      var commands = path.split(commandPattern);
      var commandArray = path.split(commandString);
  
      for (let i = 0, len = commandArray.length; i &lt; len; i++) {
        let action = commandArray[i].toUpperCase();
        if (typeof commands[i] === 'undefined') break;
  
        const array = cleanArray(commands[i].split(stringSplit));
        switch (action) {
          case "M":
            move(array, context);
            break;
          case "C":
            curveTo(array, context);
            break;
          case "Q":
            quadraticTo(array, context);
            break;
          case "L":
            lineTo(array, context);
            break;
          case "Z":
            context.closePath();
            break;
          default:
        }
      }
    }
    function makeCanvas(canvas, ctx, img){
      var svg = document.getElementById("svgTag");
      var groups = svg.getElementsByTagName("g");
      var path = groups[0].childNodes[1].getAttribute("d");
      ctx.drawImage(img, 10, 10);
      ctx.fillStyle = "black";
      console.log(path);
      draw(path, ctx);
    }
    function imageCanvas() {
      var c = document.getElementById("myCanvas");
      var ctx = c.getContext("2d");
      var img = document.createElement("IMG");
      img.addEventListener('load', function() {
        makeCanvas(c, ctx, img);
      }.bind(this), false);
      img.setAttribute("src", "https://image.ibb.co/h9CWiR/odd_size.png");
  
    }
  
    window.onload = imageCanvas();
  </code></pre>
  
  <p>Again, I have created a fiddle demonstrating this here:<a href="https://jsfiddle.net/nhoughto5/whwxtxcp/1/" rel="nofollow noreferrer">https://jsfiddle.net/nhoughto5/whwxtxcp/1/</a></p>
  
  <p>The problem is that it seems completely wrong. At first I thought that it might be an issue with the translate value in the SVG group. I added a constant at the top of the JS to easily translate it around. If you modify the translate constants to: <code>const translateX = 100, translateY = 300;</code> what it draws will move into the middle and you can see that it is fantastically wrong. </p>
  
  <p>I've stepped through my solution and checked that the data is being spliced and drawn onto the canvas in the correct order. Does canvas do something different to SVG that I'm not aware of? Not to toot my own horn but I'm fairly confident that my implementation is correct but there is something that I'm missing. </p>