{"id":6750,"date":"2017-10-24T11:11:22","date_gmt":"2017-10-24T09:11:22","guid":{"rendered":"https:\/\/anexia.com\/stagingblog\/?p=6750"},"modified":"2022-04-21T14:08:58","modified_gmt":"2022-04-21T12:08:58","slug":"meme-generator-with-jquery-and-canvas","status":"publish","type":"post","link":"https:\/\/anexia.com\/blog\/en\/meme-generator-with-jquery-and-canvas\/","title":{"rendered":"Meme Generator with jQuery and Canvas"},"content":{"rendered":"<p>In this tutorial, I will show you how to create a meme generator with the HTML element canvas. You can see the result here in my demo script:<\/p>\n<p><a href=\"https:\/\/anexia-tutorials.webduckz.com\/meme-generator\/\" target=\"_blank\" rel=\"noopener\">MEME GENERATOR<\/a><\/p>\n<p>Anyone who doesn&#8217;t know what a <a href=\"https:\/\/de.wikipedia.org\/wiki\/Internetph%C3%A4nomen\" target=\"_blank\" rel=\"noopener\">meme<\/a> is will find a brief explanation below:<\/p>\n<p>Memes are pseudo images featuring a more or less meaningful text phrase. In terms of topics, there are virtually no limitations, and memes are generally created by chance or based on the author&#8217;s own creativity. Memes have become an Internet hype, which can likely be traced back to the fact that they are easy to create.<\/p>\n<p>&nbsp;<\/p>\n<h2>CANVAS \u2013 TEACHING A BROWSER TO DRAW<\/h2>\n<p>Canvas is an HTML element with freely definable height and width \u2013 like a real physical canvas \u2013 which can be &#8222;drawn on&#8220; with the help of Javascript.<\/p>\n<p>And the functions aren&#8217;t restricted to lines and rectangles \u2013 circles, gradients, and texts can also be processed. But that&#8217;s not all: even B\u00e9zier curves and external graphics can be used (to a certain extent).  They can be rescaled or repositioned, or even cropped.<\/p>\n<p>Canvas treats each inserted object\/object group as a separate element that can be moved, scaled, or rotated individually.<\/p>\n<p><a href=\"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/10\/canvas-meme-generator.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-3015\" src=\"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/10\/canvas-meme-generator.png\" alt=\"Meme-Generator mit Canvas und jQuery\" width=\"600\" height=\"303\" srcset=\"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/10\/canvas-meme-generator.png 1920w, https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/10\/canvas-meme-generator-325x164.png 325w, https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/10\/canvas-meme-generator-300x152.png 300w, https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/10\/canvas-meme-generator-768x388.png 768w, https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/10\/canvas-meme-generator-1024x518.png 1024w\" sizes=\"(max-width: 600px) 100vw, 600px\" \/><\/a><\/p>\n<p>With our meme generator, we will be able to select any image or picture and then place two text areas on it using a few slider elements.<\/p>\n<p>Since we will only work with Javascript, we do not need a server-side script or script language (such as <a href=\"https:\/\/anexia.com\/en\/software-development\/web-development\/php-development\/\">PHP<\/a>) for these basic functions.<\/p>\n<p>&nbsp;<\/p>\n<h2>Step 1: Creating HTML markup for the configurator<\/h2>\n<p>In principle, our meme generator will consist of three parts: an <a href=\"https:\/\/anexia.com\/en\/software-development\/web-development\/htmlcss-development\/\">HTML page<\/a> with configuration options, a minimalistic CSS file (since we will work with the CSS framework Bootstrap), and a Javascript file with our logic.<\/p>\n<p>So, let&#8217;s begin with the first part, the HTML configuration page.<\/p>\n<p>Basically, we are creating a Bootstrap grid layout here (as you can see in the example screenshot above), which will display the meme generated with canvas on the left and the configuration options on the right (with the help of slider elements).<\/p>\n<pre class=\"lang:xhtml decode:true\">&lt;html&gt;\r\n\t&lt;head&gt;\r\n\t\t&lt;title&gt;Meme Generator&lt;\/title&gt;\r\n\t\t\r\n\t\t&lt;link rel=\"stylesheet\" href=\"https:\/\/maxcdn.bootstrapcdn.com\/bootstrap\/4.0.0-beta\/css\/bootstrap.min.css\" integrity=\"sha384-\/Y6pD6FV\/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\"&gt;\r\n\t\t&lt;link rel=\"stylesheet\" href=\"https:\/\/maxcdn.bootstrapcdn.com\/font-awesome\/4.7.0\/css\/font-awesome.min.css\" \/&gt;\r\n\t\t&lt;link rel=\"stylesheet\" href=\"style.css\"\/&gt;\r\n\t&lt;\/head&gt;\r\n\t&lt;body&gt;\r\n\t\r\n\t&lt;nav class=\"navbar navbar-expand-md navbar-dark bg-dark fixed-top\"&gt;\r\n\t\t&lt;a class=\"navbar-brand\" href=\"#\"&gt;Meme Generator&lt;\/a&gt;\r\n\t\t&lt;button class=\"navbar-toggler\" type=\"button\" data-toggle=\"collapse\" data-target=\"#navbarsExampleDefault\" aria-controls=\"navbarsExampleDefault\" aria-expanded=\"false\" aria-label=\"Toggle navigation\"&gt;\r\n\t\t\t&lt;span class=\"navbar-toggler-icon\"&gt;&lt;\/span&gt;\r\n\t\t&lt;\/button&gt;\r\n\r\n\t\t&lt;div class=\"collapse navbar-collapse\" id=\"navbarsExampleDefault\"&gt;\r\n\t\t\t&lt;ul class=\"navbar-nav mr-auto\"&gt;\r\n\t\t\t\t&lt;li class=\"nav-item active\"&gt;\r\n\t\t\t\t\t&lt;a class=\"nav-link\" href=\"#\"&gt;Home &lt;span class=\"sr-only\"&gt;(current)&lt;\/span&gt;&lt;\/a&gt;\r\n\t\t\t\t&lt;\/li&gt;\r\n\t\t\t\t&lt;li class=\"nav-item\"&gt;\r\n\t\t\t\t\t&lt;a class=\"nav-link\" href=\"#\"&gt;Gallery&lt;\/a&gt;\r\n\t\t\t\t&lt;\/li&gt;\r\n\t\t\t\t&lt;li class=\"nav-item\"&gt;\r\n\t\t\t\t\t&lt;a class=\"nav-link\" href=\"#\"&gt;About&lt;\/a&gt;\r\n\t\t\t\t&lt;\/li&gt;\r\n\t\t\t&lt;\/ul&gt;\r\n\t\t&lt;\/div&gt;\r\n\t&lt;\/nav&gt;\r\n\r\n\t&lt;div class=\"container\"&gt;\r\n\t\r\n\t\t&lt;div class=\"page-header\"&gt;\r\n\t\t\t&lt;h1&gt;&lt;i class=\"fa fa-2x fa-paint-brush\" aria-hidden=\"true\"&gt;&lt;\/i&gt; Create your awesome Meme now!&lt;\/h1&gt;\r\n\t\t&lt;\/div&gt;\r\n\t\r\n\t\t&lt;p&gt;&amp;nbsp;&lt;\/p&gt;\r\n\t\t\r\n\t\t&lt;div class=\"row\"&gt;\r\n\t\t\t&lt;div class=\"col-md-4\"&gt;\r\n\t\t\t\r\n\t\t\t\t&lt;!-- BEGIN: Canvas rendering of generated Meme --&gt;\r\n\t\t\t\t&lt;canvas id=\"meme\" class=\"img-thumbnail img-fluid\"&gt;\r\n\t\t\t\t\tUnfortunately your browser does not support canvas.\r\n\t\t\t\t&lt;\/canvas&gt;\r\n\t\t\t\t&lt;!-- END: Canvas rendering of generated Meme --&gt;\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t&lt;a href=\"javascript:;\" class=\"btn btn-primary btn-block\" id=\"download_meme\"&gt;\r\n\t\t\t\t\t&lt;i class=\"fa fa-download\" aria-hidden=\"true\"&gt;&lt;\/i&gt; Download\r\n\t\t\t\t&lt;\/a&gt;\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t&lt;img id=\"start-image\" src=\"image.jpg\" alt=\"\" \/&gt;\r\n\t\t\t&lt;\/div&gt;\r\n\t\t\t&lt;div class=\"col-md-8\"&gt;\r\n\t\t\t\r\n\t\t\t\t&lt;div class=\"row\"&gt;\r\n\t\t\t\t\t&lt;div class=\"col-md-12\"&gt;\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t&lt;div class=\"input-group\"&gt;\r\n\t\t\t\t\t\t\t&lt;span class=\"input-group-addon\"&gt;Image:&lt;\/span&gt;\r\n\t\t\t\t\t\t\t&lt;input type=\"file\" class=\"form-control\" id=\"imgInp\" \/&gt;\r\n\t\t\t\t\t\t&lt;\/div&gt;\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t&lt;\/div&gt;\r\n\t\t\t\t&lt;\/div&gt;\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t&lt;hr \/&gt;\r\n\t\t\t\t\r\n\t\t\t\t&lt;h3&gt;Text 1:&lt;\/h3&gt;\r\n\t\t\t\t\r\n\t\t\t\t&lt;div class=\"form-group\"&gt;\r\n\t\t\t\t\t&lt;input type=\"text\" class=\"form-control form-control-lg\" value=\"Have you expected this to be\" id=\"text_top\" \/&gt;\r\n\t\t\t\t&lt;\/div&gt;\r\n\t\t\t\t\r\n\t\t\t\t&lt;div class=\"form-group\"&gt;\r\n\t\t\t\t\t&lt;div class=\"row\"&gt;\r\n\t\t\t\t\t\t&lt;label class=\"control-label col-md-3\" for=\"text_top_offset\"&gt;Offset from top:&lt;\/label&gt;\r\n\t\t\t\t\t\t&lt;div class=\"col-md-7\"&gt;\r\n\t\t\t\t\t\t\t&lt;input style=\"width:100%\" id=\"text_top_offset\" type=\"range\" min=\"0\" max=\"500\" value=\"50\"\/&gt;\r\n\t\t\t\t\t\t&lt;\/div&gt;\r\n\t\t\t\t\t\t&lt;div class=\"col-md-2 setting-value\"&gt;\r\n\t\t\t\t\t\t\t&lt;span id=\"text_top_offset__val\"&gt;50&lt;\/span&gt;px\r\n\t\t\t\t\t\t&lt;\/div&gt;\r\n\t\t\t\t\t&lt;\/div&gt;\r\n\t\t\t\t&lt;\/div&gt;\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t&lt;p&gt;&amp;nbsp;&lt;\/p&gt;\r\n\t\t\t\t\r\n\t\t\t\t&lt;h3&gt;Text 2:&lt;\/h3&gt;\r\n\t\t\t\t\r\n\t\t\t\t&lt;div class=\"form-group\"&gt;\r\n\t\t\t\t\t&lt;input type=\"text\" class=\"form-control form-control-lg\" value=\"funny?\" id=\"text_bottom\" \/&gt;\r\n\t\t\t\t&lt;\/div&gt;\r\n\t\t\t\t\r\n\t\t\t\t&lt;div class=\"form-group\"&gt;\r\n\t\t\t\t\t&lt;div class=\"row\"&gt;\r\n\t\t\t\t\t\t&lt;label class=\"control-label col-md-3\" for=\"text_bottom_offset\"&gt;Offset from top:&lt;\/label&gt;\r\n\t\t\t\t\t\t&lt;div class=\"col-md-7\"&gt;\r\n\t\t\t\t\t\t\t&lt;input style=\"width:100%\" id=\"text_bottom_offset\" type=\"range\" min=\"0\" max=\"500\" value=\"450\"\/&gt;\r\n\t\t\t\t\t\t&lt;\/div&gt;\r\n\t\t\t\t\t\t&lt;div class=\"col-md-2 setting-value\"&gt;\r\n\t\t\t\t\t\t\t&lt;span id=\"text_bottom_offset__val\"&gt;450&lt;\/span&gt;px\r\n\t\t\t\t\t\t&lt;\/div&gt;\r\n\t\t\t\t\t&lt;\/div&gt;\r\n\t\t\t\t&lt;\/div&gt;\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t&lt;hr \/&gt;\r\n\t\t\t\t\r\n\t\t\t\t&lt;p&gt;&amp;nbsp;&lt;\/p&gt;\r\n\r\n\t\t\t\t&lt;div class=\"card\"&gt;\r\n\t\t\t\t\t&lt;div class=\"card-header\"&gt;\r\n\t\t\t\t\t\t&lt;i class=\"fa fa-cogs\" aria-hidden=\"true\"&gt;&lt;\/i&gt; More options\r\n\t\t\t\t\t&lt;\/div&gt;\r\n\t\t\t\t\t&lt;div class=\"card-body\"&gt;\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t&lt;div class=\"row\"&gt;\r\n\t\t\t\t\t\t\t&lt;div class=\"col-md-12\"&gt;\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t&lt;div class=\"form-group\"&gt;\r\n\t\t\t\t\t\t\t\t\t&lt;div class=\"row\"&gt;\r\n\t\t\t\t\t\t\t\t\t\t&lt;label class=\"control-label col-md-3\" for=\"canvas_size\"&gt;Meme size:&lt;\/label&gt;\r\n\t\t\t\t\t\t\t\t\t\t&lt;div class=\"col-md-7\"&gt;\r\n\t\t\t\t\t\t\t\t\t\t\t&lt;input style=\"width:100%\" id=\"canvas_size\" type=\"range\" min=\"0\" max=\"1000\" value=\"500\"\/&gt;\r\n\t\t\t\t\t\t\t\t\t\t&lt;\/div&gt;\r\n\t\t\t\t\t\t\t\t\t\t&lt;div class=\"col-md-2 setting-value\"&gt;\r\n\t\t\t\t\t\t\t\t\t\t\t&lt;span id=\"canvas_size__val\"&gt;500&lt;\/span&gt;px\r\n\t\t\t\t\t\t\t\t\t\t&lt;\/div&gt;\r\n\t\t\t\t\t\t\t\t\t&lt;\/div&gt;\r\n\t\t\t\t\t\t\t\t&lt;\/div&gt;\r\n\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t&lt;div class=\"form-group\"&gt;\r\n\t\t\t\t\t\t\t\t\t&lt;div class=\"row\"&gt;\r\n\t\t\t\t\t\t\t\t\t\t&lt;label class=\"control-label col-md-3\" for=\"text_font_size\"&gt;Font size:&lt;\/label&gt;\r\n\t\t\t\t\t\t\t\t\t\t&lt;div class=\"col-md-7\"&gt;\r\n\t\t\t\t\t\t\t\t\t\t\t&lt;input style=\"width:100%\" id=\"text_font_size\" type=\"range\" min=\"0\" max=\"72\" value=\"28\"\/&gt;\r\n\t\t\t\t\t\t\t\t\t\t&lt;\/div&gt;\r\n\t\t\t\t\t\t\t\t\t\t&lt;div class=\"col-md-2 setting-value\"&gt;\r\n\t\t\t\t\t\t\t\t\t\t\t&lt;span id=\"text_font_size__val\"&gt;28&lt;\/span&gt;pt\r\n\t\t\t\t\t\t\t\t\t\t&lt;\/div&gt;\r\n\t\t\t\t\t\t\t\t\t&lt;\/div&gt;\r\n\t\t\t\t\t\t\t\t&lt;\/div&gt;\r\n\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t&lt;div class=\"form-group\"&gt;\r\n\t\t\t\t\t\t\t\t\t&lt;div class=\"row\"&gt;\r\n\t\t\t\t\t\t\t\t\t\t&lt;label class=\"control-label col-md-3\" for=\"text_line_height\"&gt;Line height:&lt;\/label&gt;\r\n\t\t\t\t\t\t\t\t\t\t&lt;div class=\"col-md-7\"&gt;\r\n\t\t\t\t\t\t\t\t\t\t\t&lt;input style=\"width:100%\" id=\"text_line_height\" type=\"range\" min=\"0\" max=\"100\" value=\"15\"\/&gt;\r\n\t\t\t\t\t\t\t\t\t\t&lt;\/div&gt;\r\n\t\t\t\t\t\t\t\t\t\t&lt;div class=\"col-md-2 setting-value\"&gt;\r\n\t\t\t\t\t\t\t\t\t\t\t&lt;span id=\"text_line_height__val\"&gt;15&lt;\/span&gt;pt\r\n\t\t\t\t\t\t\t\t\t\t&lt;\/div&gt;\r\n\t\t\t\t\t\t\t\t\t&lt;\/div&gt;\r\n\t\t\t\t\t\t\t\t&lt;\/div&gt;\r\n\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t&lt;div class=\"form-group\"&gt;\r\n\t\t\t\t\t\t\t\t\t&lt;div class=\"row\"&gt;\r\n\t\t\t\t\t\t\t\t\t\t&lt;label class=\"control-label col-md-3\" for=\"text_stroke_width\"&gt;Stroke width:&lt;\/label&gt;\r\n\t\t\t\t\t\t\t\t\t\t&lt;div class=\"col-md-7\"&gt;\r\n\t\t\t\t\t\t\t\t\t\t\t&lt;input style=\"width:100%\" id=\"text_stroke_width\" type=\"range\" min=\"0\" max=\"20\" value=\"4\"\/&gt;\r\n\t\t\t\t\t\t\t\t\t\t&lt;\/div&gt;\r\n\t\t\t\t\t\t\t\t\t\t&lt;div class=\"col-md-2 setting-value\"&gt;\r\n\t\t\t\t\t\t\t\t\t\t\t&lt;span id=\"text_stroke_width__val\"&gt;4&lt;\/span&gt;pt\r\n\t\t\t\t\t\t\t\t\t\t&lt;\/div&gt;\r\n\t\t\t\t\t\t\t\t\t&lt;\/div&gt;\r\n\t\t\t\t\t\t\t\t&lt;\/div&gt;\r\n\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t&lt;\/div&gt;\r\n\t\t\t\t\t\t&lt;\/div&gt;\r\n\t\t\t\t\t\r\n\t\t\t\t\t&lt;\/div&gt;\r\n\t\t\t\t&lt;\/div&gt;\r\n\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t&lt;\/div&gt;\r\n\t\t&lt;\/div&gt;\r\n\t\t\r\n\t\t\r\n\t&lt;\/div&gt;\r\n\r\n\t\r\n\t&lt;!-- Bootstrap core JavaScript\r\n\t================================================== --&gt;\r\n\t&lt;!-- Placed at the end of the document so the pages load faster --&gt;\r\n\t&lt;script src=\"https:\/\/code.jquery.com\/jquery-3.2.1.slim.min.js\" integrity=\"sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr\/rE9\/Qpg6aAZGJwFDMVNA\/GpGFF93hXpG5KkN\" crossorigin=\"anonymous\"&gt;&lt;\/script&gt;\r\n\t&lt;script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/popper.js\/1.11.0\/umd\/popper.min.js\" integrity=\"sha384-b\/U6ypiBEHpOf\/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4\" crossorigin=\"anonymous\"&gt;&lt;\/script&gt;\r\n\t&lt;script src=\"https:\/\/maxcdn.bootstrapcdn.com\/bootstrap\/4.0.0-beta\/js\/bootstrap.min.js\" integrity=\"sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1\" crossorigin=\"anonymous\"&gt;&lt;\/script&gt;\r\n\t&lt;script src=\"app.js\"&gt;&lt;\/script&gt;\r\n\t\r\n\t&lt;\/body&gt;\r\n&lt;\/html&gt;<\/pre>\n<p>As you can see here, all you have to do is define a &#8222;<strong><em>canvas<\/em><\/strong>&#8220; HTML tag for canvas. Optionally, you can also enter inline dimensions directly, instead of via CSS definitions. The text within the canvas tag is only shown in browsers that do not support this technology.<\/p>\n<p>The slider elements are assigned their own ID we will later use via Javascript or jQuery. This not only gives us their set value, but also allows us to set their start and end range dynamically based on the image file&#8217;s metadata (its dimensions).<\/p>\n<p>&nbsp;<\/p>\n<h2>Step 2: Preparing the CSS file<\/h2>\n<p>As mentioned before, the CSS file <strong>style.css <\/strong>will be very minimalistic since we will use standard <a href=\"http:\/\/getbootstrap.com\/\">Bootstrap<\/a> elements in this tutorial.<\/p>\n<pre class=\"lang:css decode:true\">body {\r\n  padding-top: 5rem;\r\n}\r\n\r\nimg#start-image {\r\n\tposition: absolute;\r\n\tleft: -10000px;\r\n\ttop: -10000px;\r\n}\r\n\r\n.setting-value {\r\n\ttext-align: center;\r\n\tfont-weight: bold;\r\n}<\/pre>\n<p>We already embedded the Boostrap framework via its CDN (including the corresponding Javascript resources).<\/p>\n<p>The image with the ID &#8222;<em>start-image<\/em>&#8220; is simply the holder for our source image file for canvas rendering. For this reason, we will move it off screen for convenience.<\/p>\n<p>&nbsp;<\/p>\n<h2>Step 3: Embedding Javascript logic<\/h2>\n<p>To be able to embed the Javascript logic, we will first create the file named <strong>app.js<\/strong> (already linked in HTML) with the following jQuery framework.<\/p>\n<pre class=\"lang:js decode:true\">$(document).ready(function(){\r\n\r\n\t\/\/ here will be the whole application logic...\r\n\r\n});<\/pre>\n<p>All further steps will take place within this block.<\/p>\n<p>First, we will begin by initializing the canvas element with the ID &#8222;meme&#8220;:<\/p>\n<pre class=\"lang:js decode:true \">var canvas = document.getElementById('meme');\r\nctx = canvas.getContext('2d');<\/pre>\n<p>In the <strong><em>ctx<\/em><\/strong><em> <\/em>variable, within the jQuery scope we now have the application context for our canvas element, which is available via the <em><strong>canvas<\/strong><\/em><strong> <\/strong>variable.<\/p>\n<p>Let&#8217;s begin bringing our application to life by creating the main function for generating memes. First, we will create an empty function named <em>drawMeme()<\/em>.<\/p>\n<pre class=\"lang:default decode:true \">\/\/ core drawing function\r\nvar drawMeme = function() {\r\n\t\/\/ here will be our \"drawing-code\" for our memes...\r\n\r\n};<\/pre>\n<p>The actual functional logic for this will follow a bit later.<\/p>\n<p>We have already created the two text fields for the upper and lower text areas in our HTML markup as well as the slider input fields for the configuration options, so we will now register our drawMeme() function for all relevant events of these fields.<\/p>\n<p>Primarily, these are <em><strong>change<\/strong><\/em>, <em><strong>keyup<\/strong><\/em><strong><em>, <\/em><\/strong>and <em><strong>keydown<\/strong><\/em><strong> <\/strong>for the fields with text input, as well as the <em><strong>change<\/strong><\/em> event for our slider input fields.<\/p>\n<pre class=\"lang:js decode:true\">\/\/ register event listeners\r\n\r\n$(document).on('change keydown keyup', '#text_top', function() {\r\n\tdrawMeme();\r\n});\r\n\r\n$(document).on('change keydown keyup', '#text_bottom', function() {\r\n\tdrawMeme();\r\n});\r\n\r\n$(document).on('input change', '#text_top_offset', function() {\r\n\t$('#text_top_offset__val').text( $(this).val() );\r\n\tdrawMeme();\r\n});\r\n\r\n$(document).on('input change', '#text_bottom_offset', function() {\r\n\t$('#text_bottom_offset__val').text( $(this).val() );\r\n\tdrawMeme();\r\n});\r\n\r\n$(document).on('input change', '#text_font_size', function() {\r\n\t$('#text_font_size__val').text( $(this).val() );\r\n\tdrawMeme();\r\n});\r\n\r\n$(document).on('input change', '#text_line_height', function() {\r\n\t$('#text_line_height__val').text( $(this).val() );\r\n\tdrawMeme();\r\n});\r\n\r\n$(document).on('input change', '#text_stroke_width', function() {\r\n\t$('#text_stroke_width__val').text( $(this).val() );\r\n\tdrawMeme();\r\n});\r\n\r\n$(document).on('input change', '#canvas_size', function() {\r\n\t$('#canvas_size__val').text( $(this).val() );\r\n\tdrawMeme();\r\n});<\/pre>\n<p>The additional <em><strong>input<\/strong><\/em> event for these fields ensures that these handlers are also triggered when the slider input field is in use (dragging back and forth using the mouse).<\/p>\n<p>In addition, we will show the value set for these fields in the configuration form by transferring it to the corresponding element with the help of the <a href=\"http:\/\/api.jquery.com\/text\/\" target=\"_blank\" rel=\"noopener\">text<\/a> function and overwriting its content with new content.<\/p>\n<p>Now, we will begin to gradually structure our <em>drawMeme()<\/em> function.<\/p>\n<pre class=\"lang:default decode:true \">\/\/ core drawing function\r\nvar drawMeme = function() {\r\n\tvar img = document.getElementById('start-image');\r\n\r\n\tvar fontSize = parseInt( $('#text_font_size').val() );\r\n\tvar memeSize = parseInt( $('#canvas_size').val() );\r\n\t\r\n\t\/\/ set form field properties\r\n\t$('#text_top_offset').attr('max', memeSize);\r\n\t$('#text_bottom_offset').attr('max', memeSize);\r\n\t\r\n\t\r\n};<\/pre>\n<p>We will use the source image file we assigned the ID &#8222;start-image&#8220; in the <em><strong>img<\/strong><\/em><strong> <\/strong>variable. The corresponding Javascript object is now available in this variable.<\/p>\n<p>The reason why we are working with the blank Javascript object instead of the jQuery equivalent is that we need this Javascript object in this intact form for the canvas functions.<\/p>\n<p>In addition, we take the desired size for our meme from the input field, and in the next step we will set the maximum values for our offset configuration options (for adjusting the vertical placement of the texts) to limit the slider elements accordingly.<\/p>\n<p>Next, we will configure the canvas element by defining its dimensions. First, we will use the canvas function <em><a href=\"https:\/\/www.w3schools.com\/tags\/canvas_drawimage.asp\" target=\"_blank\" rel=\"noopener\">drawImage()<\/a> <\/em>to transfer the source image file that we saved in the <em><strong>img<\/strong><\/em><strong> <\/strong> variable to this element.<\/p>\n<pre class=\"lang:js decode:true\">\/\/ initialize canvas element with desired dimensions\r\ncanvas.width = memeSize;\r\ncanvas.height = memeSize;\r\n\r\nctx.clearRect(0, 0, canvas.width, canvas.height);\r\n\r\n\/\/ calculate minimum cropping dimension\r\nvar croppingDimension = img.height;\r\nif( img.width &lt; croppingDimension ){\r\n\tcroppingDimension = img.width;\r\n}\r\n\r\nctx.drawImage(img, 0, 0, croppingDimension, croppingDimension, 0, 0, memeSize, memeSize);<\/pre>\n<p>To prevent the source image from being skewed, we will use the cropping function available in canvas. We take the maximum value for this right out of our source file by comparing the height and width and determining a suitable size.<\/p>\n<p>Memes are generally square (size defined in the <strong><em>memeSize<\/em><\/strong><em> <\/em>variable), so the image file should also have a square ratio (size defined in the <strong><em>croppingDimension<\/em><\/strong><em> <\/em>variable).<\/p>\n<p>In this case, the source image file will be scaled down to the meme dimensions and cropped to a square image. To keep it simple, we will skip any other adjustments for this cropping process.<\/p>\n<p>To be able to position the texts in our meme canvas, we will write a short helper function <em>wrapText()<\/em> (outside the <em>drawMeme()<\/em> function):<\/p>\n<pre class=\"lang:js decode:true\">\/\/ build inner container for wrapping text inside\r\nvar wrapText = function(context, text, x, y, maxWidth, lineHeight, fromBottom) {\r\n\tvar pushMethod = (fromBottom) ? 'unshift' : 'push';\r\n\r\n\tlineHeight = (fromBottom) ? -lineHeight : lineHeight;\r\n\r\n\tvar lines = [];\r\n\tvar y = y;\r\n\tvar line = '';\r\n\tvar words = text.split(' ');\r\n\r\n\tfor (var n = 0; n &lt; words.length; n++) {\r\n\t\tvar testLine = line + ' ' + words[n];\r\n\t\tvar metrics = context.measureText(testLine);\r\n\t\tvar testWidth = metrics.width;\r\n\r\n\t\tif (testWidth &gt; maxWidth) {\r\n\t\t\tlines[pushMethod](line);\r\n\t\t\tline = words[n] + ' ';\r\n\t\t} else {\r\n\t\t\tline = testLine;\r\n\t\t}\r\n\t}\r\n\tlines[pushMethod](line);\r\n\r\n\tfor (var k in lines) {\r\n\t\tcontext.strokeText(lines[k], x, y + lineHeight * k);\r\n\t\tcontext.fillText(lines[k], x, y + lineHeight * k);\r\n\t}\r\n};<\/pre>\n<p>Basically, we will now transfer the canvas scope via the <em><strong>context<\/strong><\/em> parameter, a few parameters that affect the text to be inserted, as well as its position properties.<\/p>\n<p>Here, we want to use the font size and spacing to calculate concrete X and Y coordinates and transfer them to the canvas scope (<strong><em>context<\/em><\/strong> variable). You can simply take this over for now.<\/p>\n<p>Back in the <em>drawMeme()<\/em> function, we will now create the basic settings for the canvas text using our configuration fields from the HTML mask.<\/p>\n<p>Next, we will change the text input to capital letters and enter the desired Y position. The X coordinate is exactly half of the meme width, since the text should be positioned centered.<\/p>\n<pre class=\"lang:js decode:true\">ctx.lineWidth  = parseInt( $('#text_stroke_width').val() );\r\nctx.font = fontSize + 'pt sans-serif';\r\nctx.strokeStyle = 'black';\r\nctx.fillStyle = 'white';\r\nctx.textAlign = 'center';\r\nctx.textBaseline = 'top';\r\n\r\nvar text1 = $('#text_top').val();\r\ntext1 = text1.toUpperCase();\r\nx = memeSize \/ 2;\r\ny = parseInt( $('#text_top_offset').val() );\r\n\r\nvar lineHeight = fontSize + parseInt( $('#text_line_height').val() );\r\nvar maxTextAreaWidth = memeSize * 0.85;\r\n\r\nwrapText(ctx, text1, x, y, maxTextAreaWidth, lineHeight, false);<\/pre>\n<p>With the <em><strong>maxTextAreaWidth<\/strong><\/em><strong> <\/strong>variable, we will limit the maximum text width to 85%. This is primarily for visual reasons.<\/p>\n<p>We will then repeat this for the bottom text, only that we will no longer redefine the basic font settings, but instead simply overwrite them for the corresponding properties.<\/p>\n<pre class=\"lang:default decode:true\">ctx.textBaseline = 'bottom';\r\nvar text2 = $('#text_bottom').val();\r\ntext2 = text2.toUpperCase();\r\ny = parseInt( $('#text_bottom_offset').val() );\r\n\r\nwrapText(ctx, text2, x, y, maxTextAreaWidth, lineHeight, true);<\/pre>\n<p>So that you can choose your own pictures, we will now give our file input field the corresponding function:<\/p>\n<pre class=\"lang:default decode:true\">\/\/ read selected input image from upload field and display it in browser\r\n$(\"#imgInp\").change(function(){\r\n\tvar input = this;\r\n\t\r\n\tif (input.files &amp;&amp; input.files[0]) {\r\n\t\tvar reader = new FileReader();\r\n\t\t\r\n\t\treader.onload = function (e) {\r\n\t\t\t$('#start-image').attr('src', e.target.result);\r\n\t\t}\r\n\r\n\t\treader.readAsDataURL(input.files[0]);\r\n\t}\r\n\t\r\n\twindow.setTimeout(function(){\r\n\t\tdrawMeme();\r\n\t}, 500);\r\n});<\/pre>\n<p>When a new image is selected, the Javascript file reader reads the image in and sets its Base64 string as the source (&#8222;src&#8220; attribute) of our source image file (with the ID &#8222;start-image&#8220;).<\/p>\n<p>Next, we will once again trigger the <em>drawMeme()<\/em> function so that it will read in and process the new image.<\/p>\n<p>Now, something should be happening on the meme generator page if you change one of the slider elements or input fields, since at least one change event is triggered, calling the <em>drawMeme()<\/em> function.<\/p>\n<p>We will call the <em>drawMeme()<\/em> function when loading the page so that we will see some changes right when opening the page:<\/p>\n<pre class=\"lang:default decode:true \">\/\/ init at startup\r\nwindow.setTimeout(function(){\r\n\tdrawMeme();\r\n}, 100);<\/pre>\n<p>You can download this functioning example here:<\/p>\n<p><a href=\"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/10\/canvas-meme-generator_mwu.zip\">DOWNLOAD DEMO<\/a><\/p>\n<p>&nbsp;<\/p>\n<h2>Step 4: Adding an optional download link<\/h2>\n<p>You can read out the current image as a Base64 string from your canvas element with the help of the <em>toDataURL()<\/em> function at any time.<\/p>\n<p>One option would be to set this Base64 string as an &#8222;href&#8220; attribute for your download link and to specify the desired file name using the &#8222;download&#8220; attribute.<\/p>\n<pre class=\"lang:default decode:true\">$('#download_meme').click(function(e){\r\n\t$(this).attr('href', canvas.toDataURL());\r\n\t$(this).attr('download', 'meme.png');\r\n});<\/pre>\n<p>However, note that this is not supported by all browsers and therefore will not work everywhere.<\/p>\n<p>Ideally, you should send this Base64 string via <a href=\"https:\/\/api.jquery.com\/jquery.post\/\" target=\"_blank\" rel=\"noopener\">jQuery.post()<\/a> or <a href=\"http:\/\/api.jquery.com\/jquery.ajax\/\" target=\"_blank\" rel=\"noopener\">jQuery.ajax<\/a> to a server-side script that then returns the string with the corresponding <em>&#8222;Content-Type&#8220;<\/em> header (&#8222;image\/png&#8220;).<\/p>\n<p>This would ensure that the function works in all browsers.<\/p>\n<p>&nbsp;<\/p>\n<h2>Conclusion<\/h2>\n<p>Canvas is a powerful tool for drawing dynamic graphics in your browser using Javascript.<\/p>\n<p>You will most frequently find canvas in conjunction with charting libraries, since this technology is well-established in the area of statistics.<\/p>\n<p>Working with canvas is quite easy. The only thing that can get complicated is \u2013 as in our meme generator example \u2013 correctly determining\/calculating the individual positions of the generated elements.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this tutorial, I will show you how to create a meme generator with the HTML element canvas. You can see the result here in my demo script: MEME GENERATOR Anyone who doesn&#8217;t know what a meme is will find a brief explanation below: Memes are pseudo images featuring a more or less meaningful text [&hellip;]<\/p>\n","protected":false},"author":15,"featured_media":2961,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1135,2211],"tags":[1673,1677,1570],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v22.2 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Meme Generator with jQuery and Canvas - ANEXIA Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/anexia.com\/blog\/en\/meme-generator-with-jquery-and-canvas\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Meme Generator with jQuery and Canvas - ANEXIA Blog\" \/>\n<meta property=\"og:description\" content=\"In this tutorial, I will show you how to create a meme generator with the HTML element canvas. You can see the result here in my demo script: MEME GENERATOR Anyone who doesn&#8217;t know what a meme is will find a brief explanation below: Memes are pseudo images featuring a more or less meaningful text [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/anexia.com\/blog\/en\/meme-generator-with-jquery-and-canvas\/\" \/>\n<meta property=\"og:site_name\" content=\"ANEXIA Blog\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/anexiagmbh\/\" \/>\n<meta property=\"article:published_time\" content=\"2017-10-24T09:11:22+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2022-04-21T12:08:58+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ManuelWutte-Blog-Teaser.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"672\" \/>\n\t<meta property=\"og:image:height\" content=\"372\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Manuel Wutte\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@_ANEXIA\" \/>\n<meta name=\"twitter:site\" content=\"@_ANEXIA\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Manuel Wutte\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"16\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/anexia.com\/blog\/en\/meme-generator-with-jquery-and-canvas\/\",\"url\":\"https:\/\/anexia.com\/blog\/en\/meme-generator-with-jquery-and-canvas\/\",\"name\":\"Meme Generator with jQuery and Canvas - ANEXIA Blog\",\"isPartOf\":{\"@id\":\"https:\/\/anexia.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/anexia.com\/blog\/en\/meme-generator-with-jquery-and-canvas\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/anexia.com\/blog\/en\/meme-generator-with-jquery-and-canvas\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ManuelWutte-Blog-Teaser.jpg\",\"datePublished\":\"2017-10-24T09:11:22+00:00\",\"dateModified\":\"2022-04-21T12:08:58+00:00\",\"author\":{\"@id\":\"https:\/\/anexia.com\/blog\/#\/schema\/person\/926f6b9e5aeed88b145cf86d87fd09de\"},\"breadcrumb\":{\"@id\":\"https:\/\/anexia.com\/blog\/en\/meme-generator-with-jquery-and-canvas\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/anexia.com\/blog\/en\/meme-generator-with-jquery-and-canvas\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/anexia.com\/blog\/en\/meme-generator-with-jquery-and-canvas\/#primaryimage\",\"url\":\"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ManuelWutte-Blog-Teaser.jpg\",\"contentUrl\":\"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ManuelWutte-Blog-Teaser.jpg\",\"width\":672,\"height\":372},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/anexia.com\/blog\/en\/meme-generator-with-jquery-and-canvas\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/anexia.com\/blog\/de\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Meme Generator with jQuery and Canvas\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/anexia.com\/blog\/#website\",\"url\":\"https:\/\/anexia.com\/blog\/\",\"name\":\"ANEXIA Blog\",\"description\":\"[:de] ANEXIA Blog - Technischen Themen, Anexia News und Insights [:]\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/anexia.com\/blog\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"de\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/anexia.com\/blog\/#\/schema\/person\/926f6b9e5aeed88b145cf86d87fd09de\",\"name\":\"Manuel Wutte\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/anexia.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/9528a61f48f4294cd5f7cd8a4141bd55?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/9528a61f48f4294cd5f7cd8a4141bd55?s=96&d=mm&r=g\",\"caption\":\"Manuel Wutte\"},\"url\":\"https:\/\/anexia.com\/blog\/author\/mwu\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Meme Generator with jQuery and Canvas - ANEXIA Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/anexia.com\/blog\/en\/meme-generator-with-jquery-and-canvas\/","og_locale":"de_DE","og_type":"article","og_title":"Meme Generator with jQuery and Canvas - ANEXIA Blog","og_description":"In this tutorial, I will show you how to create a meme generator with the HTML element canvas. You can see the result here in my demo script: MEME GENERATOR Anyone who doesn&#8217;t know what a meme is will find a brief explanation below: Memes are pseudo images featuring a more or less meaningful text [&hellip;]","og_url":"https:\/\/anexia.com\/blog\/en\/meme-generator-with-jquery-and-canvas\/","og_site_name":"ANEXIA Blog","article_publisher":"https:\/\/www.facebook.com\/anexiagmbh\/","article_published_time":"2017-10-24T09:11:22+00:00","article_modified_time":"2022-04-21T12:08:58+00:00","og_image":[{"width":672,"height":372,"url":"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ManuelWutte-Blog-Teaser.jpg","type":"image\/jpeg"}],"author":"Manuel Wutte","twitter_card":"summary_large_image","twitter_creator":"@_ANEXIA","twitter_site":"@_ANEXIA","twitter_misc":{"Verfasst von":"Manuel Wutte","Gesch\u00e4tzte Lesezeit":"16\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/anexia.com\/blog\/en\/meme-generator-with-jquery-and-canvas\/","url":"https:\/\/anexia.com\/blog\/en\/meme-generator-with-jquery-and-canvas\/","name":"Meme Generator with jQuery and Canvas - ANEXIA Blog","isPartOf":{"@id":"https:\/\/anexia.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/anexia.com\/blog\/en\/meme-generator-with-jquery-and-canvas\/#primaryimage"},"image":{"@id":"https:\/\/anexia.com\/blog\/en\/meme-generator-with-jquery-and-canvas\/#primaryimage"},"thumbnailUrl":"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ManuelWutte-Blog-Teaser.jpg","datePublished":"2017-10-24T09:11:22+00:00","dateModified":"2022-04-21T12:08:58+00:00","author":{"@id":"https:\/\/anexia.com\/blog\/#\/schema\/person\/926f6b9e5aeed88b145cf86d87fd09de"},"breadcrumb":{"@id":"https:\/\/anexia.com\/blog\/en\/meme-generator-with-jquery-and-canvas\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/anexia.com\/blog\/en\/meme-generator-with-jquery-and-canvas\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/anexia.com\/blog\/en\/meme-generator-with-jquery-and-canvas\/#primaryimage","url":"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ManuelWutte-Blog-Teaser.jpg","contentUrl":"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ManuelWutte-Blog-Teaser.jpg","width":672,"height":372},{"@type":"BreadcrumbList","@id":"https:\/\/anexia.com\/blog\/en\/meme-generator-with-jquery-and-canvas\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/anexia.com\/blog\/de\/"},{"@type":"ListItem","position":2,"name":"Meme Generator with jQuery and Canvas"}]},{"@type":"WebSite","@id":"https:\/\/anexia.com\/blog\/#website","url":"https:\/\/anexia.com\/blog\/","name":"ANEXIA Blog","description":"[:de] ANEXIA Blog - Technischen Themen, Anexia News und Insights [:]","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/anexia.com\/blog\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"de"},{"@type":"Person","@id":"https:\/\/anexia.com\/blog\/#\/schema\/person\/926f6b9e5aeed88b145cf86d87fd09de","name":"Manuel Wutte","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/anexia.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/9528a61f48f4294cd5f7cd8a4141bd55?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/9528a61f48f4294cd5f7cd8a4141bd55?s=96&d=mm&r=g","caption":"Manuel Wutte"},"url":"https:\/\/anexia.com\/blog\/author\/mwu\/"}]}},"lang":"en","translations":{"en":6750,"de":3013},"amp_enabled":true,"pll_sync_post":[],"_links":{"self":[{"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/posts\/6750"}],"collection":[{"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/users\/15"}],"replies":[{"embeddable":true,"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/comments?post=6750"}],"version-history":[{"count":1,"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/posts\/6750\/revisions"}],"predecessor-version":[{"id":6753,"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/posts\/6750\/revisions\/6753"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/media\/2961"}],"wp:attachment":[{"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/media?parent=6750"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/categories?post=6750"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/tags?post=6750"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}