{"id":356,"date":"2011-09-06T14:28:31","date_gmt":"2011-09-06T14:28:31","guid":{"rendered":"http:\/\/www.sitekickr.com\/blog\/?p=356"},"modified":"2011-09-06T14:35:24","modified_gmt":"2011-09-06T14:35:24","slug":"pure-javascript-css-photo-cropping-tool","status":"publish","type":"post","link":"https:\/\/www.sitekickr.com\/blog\/pure-javascript-css-photo-cropping-tool\/","title":{"rendered":"Pure JavaScript \/ CSS photo cropping tool"},"content":{"rendered":"<p>If you don&#39;t have image manipulation capabilities available on your server, fortunately, you can still implement a basic photo cropping tool using pure CSS &amp; JavaScript.<\/p>\n<p>Key CSS Ingredients:<\/p>\n<ul>\n<li>Negative margins<\/li>\n<li>Overflow property<\/li>\n<\/ul>\n<p>Key JavaScript Ingredients:<\/p>\n<ul>\n<li>jQuery<\/li>\n<li>jQuery UI<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p>On the cropping tool side, you can leverage jQuery mobile&#39;s draggable and resizeable tools to create a very basic UI for cropping a photo.<\/p>\n<p>&nbsp;<\/p>\n<h2>Cropping Tool<\/h2>\n<h3>The HTML<\/h3>\n<p><code>&lt;div id=&quot;wrapper&quot;&gt;<br \/>\n\t&nbsp;&nbsp;&nbsp; &lt;img src=&quot;myimage.jpg&quot; alt=&quot;&quot; id=&quot;image&quot; \/&gt;<br \/>\n\t&nbsp;&nbsp;&nbsp; &lt;span id=&quot;thumb&quot;&gt;&lt;\/span&gt; &lt;!-- the cropping boundaries --&gt;<br \/>\n\t&lt;\/div&gt;<\/code><\/p>\n<h3>The CSS<\/h3>\n<p><code>#wrapper { position: relative; width: <em><strong>maxImageWidth<\/strong><\/em>px; height: <em><strong>maxImageHeight<\/strong><\/em>px; }<br \/>\n\t#image { position: absolute; top: 0; left: 0; max-width: <strong><em>maxImageWidth<\/em><\/strong>px; max-height: <em><strong>maxImageHeight<\/strong><\/em>px; }<br \/>\n\t#thumb { position: absolute; top: 0; left: 0; width: <strong><em>cropWidth<\/em><\/strong>px; height: <em><strong>cropHeight<\/strong><\/em>px; border: 2px dashed #aaa; cursor: move;&nbsp; }&nbsp;&nbsp;&nbsp; <\/p>\n<p>\t<\/code><\/p>\n<h3>The jQuery<\/h3>\n<p><code>var width = $(&#39;img&#39;).width();<br \/>\n\tvar height = $(&#39;img&#39;).height();<br \/>\n\t$(&#39;img&#39;).resizable({<br \/>\n\t&nbsp;&nbsp;&nbsp; aspectRatio : true,<br \/>\n\t&nbsp;&nbsp;&nbsp; containment: &#39;parent&#39;,<br \/>\n\t&nbsp;&nbsp;&nbsp; minWidth: <em><strong>cropWidth<\/strong><\/em>,<br \/>\n\t&nbsp;&nbsp;&nbsp; minHeight: <em><strong>cropHeight<\/strong><\/em>,<br \/>\n\t&nbsp;&nbsp;&nbsp; handles: &#39;se&#39;,<br \/>\n\t&nbsp;&nbsp;&nbsp; stop : function(event, ui) {<br \/>\n\t&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; var width = $(&#39;img&#39;).width();<br \/>\n\t&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; var height = $(&#39;img&#39;).height();<br \/>\n\t&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; $(&#39;#thumb&#39;).draggable(&#39;option&#39;, &#39;containment&#39;, [0, 0, width - <em><strong>cropWidth<\/strong><\/em>, height - <em><strong>cropHeight<\/strong><\/em>]);<br \/>\n\t&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; $.ajax({<br \/>\n\t&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; url: &#39;updateTable.php?id=&#39; + id + &#39;&amp;width=&#39; + width + &#39;&amp;height=&#39; + height<br \/>\n\t&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; })<br \/>\n\t&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp; <br \/>\n\t});<br \/>\n\t$(&#39;#thumb&#39;).draggable({<br \/>\n\t&nbsp;&nbsp;&nbsp; containment : [0, 0, width - <strong><em>cropWidth<\/em><\/strong>, height - <em><strong>cropHeight<\/strong><\/em>],<br \/>\n\t&nbsp;&nbsp;&nbsp; stop : function(event, ui) {<br \/>\n\t&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; $.ajax({<br \/>\n\t&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; url: &#39;updateTable.php?id=&#39; + id + &#39;&amp;x=&#39; + ui.position.left + &#39;&amp;y=&#39; + ui.position.top<br \/>\n\t&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; })<br \/>\n\t&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp; <br \/>\n\t});<\/code><\/p>\n<p>Note the php scripts used within the jQuery AJAX calls.&nbsp; These simply contain the code which will update your database table with the new width, height, x, y positions of the cropping region and image size.<br \/>\n\t&nbsp;<\/p>\n<p>One the front end, we make use of the CSS properties mentioned above (negative margins and overflow) to effectively crop the full photo within a wrapper.<\/p>\n<h2>Front End<\/h2>\n<h3>The HTML<\/h3>\n<p><code>&lt;span id=&quot;photo-wrapper&quot;&gt;<br \/>\n\t&nbsp; &lt;img src=&quot;myimage.jpg&quot; <br \/>\n\t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; width=&quot;&lt;?php echo $widthFromDB; ?&gt;&quot; <br \/>\n\t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; height=&quot;&lt;?php echo $heightFromDB;?&gt;&quot; <br \/>\n\t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; style=&quot;margin: -&lt;?php echo $yFromDB; ?&gt;px 0 0 -&lt;?php echo $xFromDB; ?&gt;px;&quot; <br \/>\n\t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; alt=&quot;&quot; \/&gt;<br \/>\n\t&lt;\/span&gt;<br \/>\n\t<\/code><\/p>\n<h3>The CSS<\/h3>\n<p><code>#photo-wrapper { display: block; width: <em><strong>cropWidth<\/strong><\/em>px; height: <em><strong>cropHeight<\/strong><\/em>px; overflow: hidden; }<\/p>\n<p>\t<\/code><\/p>\n","protected":false},"excerpt":{"rendered":"<p>If you don&#39;t have image manipulation capabilities available on your server, fortunately, you can still implement a basic photo cropping tool using pure CSS &amp;&hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"amp_status":""},"categories":[12,14,5],"tags":[112],"_links":{"self":[{"href":"https:\/\/www.sitekickr.com\/blog\/wp-json\/wp\/v2\/posts\/356"}],"collection":[{"href":"https:\/\/www.sitekickr.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.sitekickr.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.sitekickr.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.sitekickr.com\/blog\/wp-json\/wp\/v2\/comments?post=356"}],"version-history":[{"count":0,"href":"https:\/\/www.sitekickr.com\/blog\/wp-json\/wp\/v2\/posts\/356\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.sitekickr.com\/blog\/wp-json\/wp\/v2\/media?parent=356"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sitekickr.com\/blog\/wp-json\/wp\/v2\/categories?post=356"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sitekickr.com\/blog\/wp-json\/wp\/v2\/tags?post=356"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}