Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>This can be accomplished with Fabric using the <code>clipTo</code> property, but you have to 'reverse' the transformations (scale and rotation), in the <code>clipTo</code> function.</p> <p>When you use the <code>clipTo</code> property in Fabric, the scaling and rotation are applied <em>after</em> the clipping, which means that the clipping is scaled and rotated with the image. You have to counter this by applying the exact <em>reverse</em> of the transformations in the <code>clipTo</code> property function.</p> <p>My solution involves having a <code>Fabric.Rect</code> serve as the 'placeholder' for the clip region (this has advantages because you can use Fabric to move the object around and thus the clip region.</p> <p>Please note that my solution uses the <a href="http://lodash.com/">Lo-Dash</a> utility library, particularly for <a href="http://lodash.com/docs#bind"><code>_.bind()</code></a> (see code for context).</p> <h1><a href="http://jsfiddle.net/natchiketa/gXZJf/">Example Fiddle</a></h1> <hr> <h1>Breakdown</h1> <h2>1. Initialize Fabric</h2> <p>First we want our canvas, of course:</p> <pre class="lang-js prettyprint-override"><code>var canvas = new fabric.Canvas('c'); </code></pre> <h2>2. Clip Region</h2> <pre class="lang-js prettyprint-override"><code>var clipRect1 = new fabric.Rect({ originX: 'left', originY: 'top', left: 180, top: 10, width: 200, height: 200, fill: 'none', stroke: 'black', strokeWidth: 2, selectable: false }); </code></pre> <p>We give these <code>Rect</code> objects a name property, <code>clipFor</code>, so the <code>clipTo</code> functions can find the one by which they want to be clipped:</p> <pre class="lang-js prettyprint-override"><code>clipRect1.set({ clipFor: 'pug' }); canvas.add(clipRect1); </code></pre> <p>There doesn't <em>have</em> to be an actual object for the clip region, but it makes it easier to manage, as you're able to move it around using Fabric.</p> <h2>3. Clipping Function</h2> <p>We define the function which will be used by the images' <code>clipTo</code> properties separately to avoid code duplication:</p> <p>Since the <code>angle</code> property of the Image object is stored in degrees, we'll use this to convert it to radians. </p> <pre class="lang-js prettyprint-override"><code>function degToRad(degrees) { return degrees * (Math.PI / 180); } </code></pre> <p><code>findByClipName()</code> is a convenience function, which is using <a href="http://lodash.com/">Lo-Dash</a>, to find the with the <code>clipFor</code> property for the Image object to be clipped (for example, in the image below, <code>name</code> will be <code>'pug'</code>):</p> <pre class="lang-js prettyprint-override"><code>function findByClipName(name) { return _(canvas.getObjects()).where({ clipFor: name }).first() } </code></pre> <p>And this is the part that does the work:</p> <pre class="lang-js prettyprint-override"><code>var clipByName = function (ctx) { var clipRect = findByClipName(this.clipName); var scaleXTo1 = (1 / this.scaleX); var scaleYTo1 = (1 / this.scaleY); ctx.save(); ctx.translate(0,0); ctx.rotate(degToRad(this.angle * -1)); ctx.scale(scaleXTo1, scaleYTo1); ctx.beginPath(); ctx.rect( clipRect.left - this.left, clipRect.top - this.top, clipRect.width, clipRect.height ); ctx.closePath(); ctx.restore(); } </code></pre> <p><em>NOTE</em>: <em>See below for and explanation of the use of <code>this</code> in the function above.</em></p> <h2>4. <code>fabric.Image</code> object using <code>clipByName()</code></h2> <p>Finally, the image can be instantiated and made to use the <code>clipByName</code> function like this:</p> <pre class="lang-js prettyprint-override"><code>var pugImg = new Image(); pugImg.onload = function (img) { var pug = new fabric.Image(pugImg, { angle: 45, width: 500, height: 500, left: 230, top: 170, scaleX: 0.3, scaleY: 0.3, clipName: 'pug', clipTo: function(ctx) { return _.bind(clipByName, pug)(ctx) } }); canvas.add(pug); }; pugImg.src = 'http://fabricjs.com/lib/pug.jpg'; </code></pre> <h3>What does <code>_.bind()</code> do?</h3> <p>Note that the reference is wrapped in the <a href="http://lodash.com/docs#bind"><code>_.bind()</code></a> function.</p> <p>I'm using <code>_.bind()</code> for the following two reasons:</p> <ol> <li>We need to pass a reference <code>Image</code> object to <code>clipByName()</code></li> <li>The <code>clipTo</code> property is passed the canvas context, not the object.</li> </ol> <p>Basically, <code>_.bind()</code> lets you create a version of the function that uses the object you specify as the <code>this</code> context.</p> Sources <ol> <li><a href="http://lodash.com/docs#bind">http://lodash.com/docs#bind</a></li> <li><a href="http://fabricjs.com/docs/fabric.Object.html#clipTo">http://fabricjs.com/docs/fabric.Object.html#clipTo</a></li> <li><a href="http://html5.litten.com/understanding-save-and-restore-for-the-canvas-context/">http://html5.litten.com/understanding-save-and-restore-for-the-canvas-context/</a></li> </ol>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload