var isDragging = false;
var dragOffsetX = 0;
var dragOffsetY = 0;
var textParts = [];
var x = canvas.width / 2;
var y = textSizeTop + padding;
var lh = 1;
var textSize = 10;
var textSizeTop = 10;

// CANVAS.js plugin
(function (window, document) {
  /**
   * CANVAS Plugin - Adding line breaks to canvas
   * @arg {string} [str=Hello World] - text to be drawn
   * @arg {number} [x=0]             - top left x coordinate of the text
   * @arg {number} [y=textSize]      - top left y coordinate of the text
   * @arg {number} [w=canvasWidth]   - maximum width of drawn text
   * @arg {number} [lh=1]            - line height
   * @arg {number} [method=fill]     - text drawing method, if 'none', text will not be rendered
   */
  CanvasRenderingContext2D.prototype.drawBreakingText = function (
    str,
    x,
    y,
    w,
    lh,
    method
  ) {
    // local variables and defaults
    var textSize = parseInt(this.font.replace(/\D/gi, ''));
    var textParts = [];
    var textPartsNo = 0;
    var words = [];
    var currLine = '';
    var testLine = '';
    str = str || '';
    x = x || 0;
    y = y || 0;
    w = w || this.canvas.width;
    lh = lh || 1;
    method = method || 'fill';

    // manual linebreaks
    textParts = str.split('\n');
    textPartsNo = textParts.length;

    // split the words of the parts
    for (var i = 0; i < textParts.length; i++) {
      words[i] = textParts[i].split(&#039; &#039;);
    }

    // now that we have extracted the words
    // we reset the textParts
    textParts = [];

    // calculate recommended line breaks
    // split between the words
    for (var i = 0; i < textPartsNo; i++) {
      // clear the testline for the next manually broken line
      currLine = &#039;&#039;;

      for (var j = 0; j < words[i].length; j++) {
        testLine = currLine + words[i][j] + &#039; &#039;;

        // check if the testLine is of good width
        if (this.measureText(testLine).width > w && j > 0) {
          textParts.push(currLine);
          currLine = words[i][j] + &#039; &#039;;
        } else {
          currLine = testLine;
        }
      }
      // replace is to remove trailing whitespace
      textParts.push(currLine);
    }

    // render the text on the canvas
    for (var i = 0; i < textParts.length; i++) {
      if (method === &#039;fill&#039;) {
        this.fillText(
          textParts[i].replace(/((\s*\S+)*)\s*/, &#039;$1&#039;),
          x,
          y + textSize * lh * i
        );
      } else if (method === &#039;stroke&#039;) {
        this.strokeText(
          textParts[i].replace(/((\s*\S+)*)\s*/, &#039;$1&#039;),
          x,
          y + textSize * lh * i
        );
      }
    }
  };
})(window, document);

// Initialize canvas and context
var canvas = document.createElement(&#039;canvas&#039;);
var canvasWrapper = document.getElementById(&#039;canvasWrapper&#039;);
canvasWrapper.appendChild(canvas);
canvas.width = 500;
canvas.height = 500;
var ctx = canvas.getContext(&#039;2d&#039;);

// Add event listeners
canvas.addEventListener(&#039;mousedown&#039;, onMouseDown);
canvas.addEventListener(&#039;mouseup&#039;, onMouseUp);
canvas.addEventListener(&#039;mousemove&#039;, onMouseMove);
canvas.addEventListener(&#039;mouseout&#039;, onMouseUp);

// Set initial values
var padding = 15;
var textTop = &#039;i don\&#039;t always make a meme&#039;;
var textMiddle = &#039;but when i do, I use ninivert\&#039;s generator&#039;;
var textBottom = &#039;but when i do, I use ninivert\&#039;s generator&#039;;
var textSizeMiddle = 10;
var textSizeBottom = 10;
var image = document.createElement(&#039;img&#039;);

// Load image
image.src = &#039;https://imgflip.com/s/meme/The-Most-Interesting-Man-In-The-World.jpg&#039;;
image.onload = function () {
  drawMeme();
};

// Draw meme on canvas
function drawMeme() {
  // Clear canvas
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  // Draw image
  ctx.drawImage(image, 0, 0, canvas.width, canvas.height);

  // Set text styles
  ctx.font = textSizeTop + &#039;px Impact&#039;;
  ctx.fillStyle = &#039;#ffffff&#039;;
  ctx.strokeStyle = &#039;#000000&#039;;
  ctx.lineWidth = 2;
  ctx.textAlign = &#039;center&#039;;

  // Draw top text
  ctx.drawBreakingText(
    textTop,
    canvas.width / 2,
    textSizeTop + padding,
    canvas.width - 2 * padding,
    lh,
    &#039;fill&#039;
  );

  // Set middle text styles
  ctx.font = textSizeMiddle + &#039;px Impact&#039;;

  // Draw middle text
  ctx.drawBreakingText(
    textMiddle,
    canvas.width / 2,
    canvas.height / 2,
    canvas.width - 2 * padding,
    lh,
    &#039;fill&#039;
  );

  // Set bottom text styles
  ctx.font = textSizeBottom + &#039;px Impact&#039;;

  // Draw bottom text
  ctx.drawBreakingText(
    textBottom,
    canvas.width / 2,
    canvas.height - padding,
    canvas.width - 2 * padding,
    lh,
    &#039;fill&#039;
  );
}

// Handle mouse down event
function onMouseDown(e) {
  var mouseX = e.clientX - canvas.getBoundingClientRect().left;
  var mouseY = e.clientY - canvas.getBoundingClientRect().top;

  if (
    mouseX > 0 &&
    mouseX < canvas.width &&
    mouseY > 0 &&
    mouseY < canvas.height
  ) {
    isDragging = true;
    dragOffsetX = mouseX - x;
    dragOffsetY = mouseY - y;
  }
}

// Handle mouse up event
function onMouseUp() {
  isDragging = false;
}

// Handle mouse move event
function onMouseMove(e) {
  if (isDragging) {
    x = e.clientX - canvas.getBoundingClientRect().left - dragOffsetX;
    y = e.clientY - canvas.getBoundingClientRect().top - dragOffsetY;
    drawMeme();
  }
}

Add a code snippet to your website: www.paste.org