Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Like markE said, this <a href="http://www.html5canvastutorials.com/labs/html5-canvas-drag-and-drop-resize-and-invert-images/" rel="noreferrer">tutorial</a> on Eric's (creator of KineticJS) tutorial site is the basis for all free transforming within KineticJS.</p> <p>I'll go into detail about the actual free transform logic, there are 2 main functions:</p> <pre><code>function addAnchor(group, x, y, name) { var stage = group.getStage(); var layer = group.getLayer(); //Create the anchor shape var anchor = new Kinetic.Circle({ x: x, y: y, stroke: '#666', fill: '#ddd', strokeWidth: 2, radius: 8, name: name, draggable: true, dragOnTop: false }); //Calls the update function which handles the transform logic anchor.on('dragmove', function() { update(this); layer.draw(); }); //When the anchor is selected, we want to turn dragging off for the group //This is so that only the anchor is draggable, and we can transform instead of drag anchor.on('mousedown touchstart', function() { group.setDraggable(false); this.moveToTop(); }); //Turn back on draggable for the group anchor.on('dragend', function() { group.setDraggable(true); layer.draw(); }); // add hover styling anchor.on('mouseover', function() { var layer = this.getLayer(); document.body.style.cursor = 'pointer'; this.setStrokeWidth(4); layer.draw(); }); anchor.on('mouseout', function() { var layer = this.getLayer(); document.body.style.cursor = 'default'; this.setStrokeWidth(2); layer.draw(); }); group.add(anchor); } </code></pre> <p>The <code>addAnchor</code> function, like the name says, adds a single anchor (or free transform handle) to a <code>Kinetic.Group</code>. By default it uses a <code>Kinetic.Circle</code> but really you can use any shape you want.</p> <ul> <li><code>group</code> - the group to add the anchor to</li> <li><code>x</code> - the x position of the anchor</li> <li><code>y</code> - the y position of the anchor</li> <li><code>name</code> - name of the anchor (usually describe which position the anchor represents, like <strong>topLeft</strong> or <strong>bottomRight</strong></li> </ul> <p>You'll notice a bunch of <code>events</code> attached to the newly created anchor, most of these are pretty straight-forward but the one you want to pay attention to is the <code>dragmove</code> event - this event is the one that calls the <code>update</code> function <strong>which handles all the logic for transforming</strong> the group/node. It's useful to note that the <code>update</code> function is called for every pixel that you are dragging an anchor.</p> <p>The tutorial uses 4 corner anchors (thus calling addAnchor 4 times for each group/node), but if you wanted 8 anchors (4 corners - 4 sides) then you just have to adjust the logic to position the anchors correctly and to move the anchors properly when transforming.</p> <p>By the way, <strong>the reason we're adding Anchors to a Group</strong>, is because we need them to group with the node in question, and stick with each node through dragging and transforming.</p> <p>The second method is the <code>update</code> function:</p> <pre><code>function update(activeAnchor) { var group = activeAnchor.getParent(); //Get each anchor inside the group, by name. Keep a standard set of names for every anchor you use and note they have to be names not ids because there will be multiple anchors named .topLeft in your app var topLeft = group.get('.topLeft')[0]; var topRight = group.get('.topRight')[0]; var bottomRight = group.get('.bottomRight')[0]; var bottomLeft = group.get('.bottomLeft')[0]; var image = group.get('.image')[0]; var anchorX = activeAnchor.getX(); var anchorY = activeAnchor.getY(); // update anchor positions switch (activeAnchor.getName()) { case 'topLeft': //When topLeft is being dragged, topRight has to update in the Y-axis //And bottomLeft has to update in the X-axis topRight.setY(anchorY); bottomLeft.setX(anchorX); break; case 'topRight': topLeft.setY(anchorY); bottomRight.setX(anchorX); break; case 'bottomRight': bottomLeft.setY(anchorY); topRight.setX(anchorX); break; case 'bottomLeft': bottomRight.setY(anchorY); topLeft.setX(anchorX); break; } image.setPosition(topLeft.getPosition()); //New height and width are calculated with a little math //by calculating the distance between the update anchor positions. var width = topRight.getX() - topLeft.getX(); var height = bottomLeft.getY() - topLeft.getY(); if(width &amp;&amp; height) { image.setSize(width, height); } } </code></pre> <p>The <code>update</code> function only takes one argument: the <code>activeAnchor</code> which is the anchor being dragged.</p> <p>After that, it selects the other anchors within the group (using static names that you need to give each node and keep consistent throughout your app) so that we can translate their positions while the <code>activeAnchor</code> is being dragged.</p> <p>The switch statement can get pretty large if you use 8 anchors instead of 4. This is because you need to consider translating almost all the other anchors while dragging one of them. </p> <p>For an 8 anchor example: If you drag the <code>topLeft</code> anchor, you need to update the <strong>y</strong> position of the <code>topRight</code> anchor, the <strong>x</strong> position of the <code>bottomLeft</code> anchor, and for the <code>topMid</code> and <code>leftMid</code> anchors you need to adjust both the <strong>x,y</strong> values to stay in between the other anchors. </p> <p>After updating the anchor position, the function handles the logic to resize the shape. Notice that the shape is selected by <code>var image = group.get('.image')[0];</code> But, what you can do is use the <code>get</code> function to select by type and do something like:</p> <p><code>var shape = group.get('Shape')[0];</code></p> <p>Obviously this will work best if you just have <strong>1 shape per group</strong> (to transform) + 4 or 8 anchors.</p> <p>Let me know if you have any other questions or comments! Good luck!</p>
 

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