1

Here is the structure I have

Layer:
  ParentGroup:
     -Kinetic Image 
     -ChildGroup 
        - Kinetic rectangle
        - Kinetic Text

On my kinetic image (that I retrieve from the server), there is a region of interest. This region of interest is shown by a rectangle (kinetic rectangle here). And I write some label inside this region (which is the kinetic text).

I would like to apply some manipulations to the whole group. Translation is ok, but I have problems with zoom and rotation. Here is my zoom function

function zoomIn() {
      var scale=parentGroup.getScale();
      scale.x *= zoomFactor; //zoomFactor is a global variable
      scale.y *= zoomFactor;
      parentGroup.setScale(scale); 
      layer.draw()
}

What happened here is that the group was zoomed in but translated (right and down) at the same time. If I keep zooming, the image goes out of the canvas. I tried, before drawing the layer : parentGroup.setPosition (0,0); //although I know that I've never modified this position, but nothing changed.

I read here KineticJS Canvas - Scale group from center point that it is maybe a problem of center of zooming. But as I don't set any height or width to may parentGroup, I didn't know how to adapt my code.

What's wrong with what I have right now?

ekad
  • 14,436
  • 26
  • 44
  • 46
user1499220
  • 419
  • 4
  • 12
  • 23
  • Nicely written question, good job! Unfortunately with this type of problem, it would be much easier to help you if you could supply us with a jsfiddle.. Although, markE did mention in the comments of the answer you linked, that if you don't set Height or Width of **parentGroup**, then you can set an arbitrary centre point to zoom towards. – projeqht Aug 02 '13 at 18:21
  • Well, actually, I wrote a simplified version of the code that I have. I'm not sure I can put it in a jsfiddle. But I read again markE's comment and I think that's what I need to do. As I want to set the center of the zoom to the center of the canvas, I set the position of the group to (innerWidth()/2, innerHeight()/2) . but it didn't work .. – user1499220 Aug 02 '13 at 20:35

1 Answers1

2

KineticJS: How to Zoom, Rotate and Drag a Group

[simplified the original answer based on better understanding of questioners needs]

Coding becomes much simpler since you allow your registration point for your group to be its centerpoint.

The registration point is the scaling point for scale transforms and the rotation point for rotations.

Here is how to set the registration point to the center of the group:

  // set the group offset to the group’s centerpoint

  parentGroup.setOffset(parentGroup.getWidth()/2,parentGroup.getHeight()/2);

After setting the registration point, just use group.setScale and group.rotateDeg normally:

  // scale the group from its centerpoint

  parentGroup.setScale(parentGroup.getScale().x+0.10);

  // rotate the group at its centerpoint

  parentGroup.rotateDeg(30);

Here is code and a Fiddle: http://jsfiddle.net/m1erickson/XWW7Z/

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
    <script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.5.4.min.js"></script>

<style>
body{ padding:15px; }
#container{
  border:solid 1px #ccc;
  margin-top: 10px;
  width:400px;
  height:400px;
}
</style>        
<script>
$(function(){

    var stage = new Kinetic.Stage({
      container: 'container',
      width: 400,
      height: 400
    });
    var layer = new Kinetic.Layer();
    stage.add(layer);


    // parentGroup is used in jquery events
    // so make it global
    var parentGroup;

    // load the image and then start the app
    var image=new Image();
    image.onload=function(){
        start();
    }
    image.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house-icon.png";

    // build everything, wire events
    function start(){

          parentGroup=new Kinetic.Group({
              x:image.width/2,
              y:image.height/2,
              width:image.width,
              height:image.height,
              draggable:true
          });
          parentGroup.setOffset(parentGroup.getWidth()/2,parentGroup.getHeight()/2);
          layer.add(parentGroup);

          var kImage=new Kinetic.Image({
              image:image,
              x:0,
              y:0,
              width:image.width,
              height:image.height
          });
          parentGroup.add(kImage);

          var childGroup=new Kinetic.Group({
              x:0,
              y:0,
              width:100,
              height:50
          });
          parentGroup.add(childGroup);

          // this outline rect is just for illustration
          var boundingRect=new Kinetic.Rect({
              x:0,
              y:0,
              width:parentGroup.getWidth(),
              height:parentGroup.getHeight(),
              stroke:"black",
              strokeWidth:.75
          });
          parentGroup.add(boundingRect);

          var childRect=new Kinetic.Rect({
              x:0,
              y:0,
              width:105,
              height:25,
              stroke:"lightgray",
              fill:"skyblue"
          });
          childGroup.add(childRect);

          var childText=new Kinetic.Text({
              x:5,
              y:3,
              fontSize:18,
              text:"Hello, World",
              fill:"blue"
          });
          childGroup.add(childText);


          layer.draw();


          // scale up by +0.10 at parentGroup registration point
          $("#larger").click(function(){
              parentGroup.setScale(parentGroup.getScale().x+0.10);
              layer.draw();
          });

          // scale down by +0.10 at parentGroup registration point
          $("#smaller").click(function(){
              parentGroup.setScale(parentGroup.getScale().x-0.10);
              layer.draw();
          });

          // rotate CW by 30 degrees at parentGroup registration point
          $("#rotateCW").click(function(){
              parentGroup.rotateDeg(30);
              layer.draw();
          });
          // rotate CCW by 30 degrees at parentGroup registration point
          $("#rotateCCW").click(function(){
              parentGroup.rotateDeg(-30);
              layer.draw();
          });

    } 


}); // end $(function(){});

</script>       
</head>

<body>
    <button id="larger">Larger</button>
    <button id="smaller">Smaller</button>
    <button id="rotateCW">Rotate clockwise</button>
    <button id="rotateCCW">Rotate CCW</button>
    <div id="container"></div>
</body>
</html>
markE
  • 102,905
  • 11
  • 164
  • 176
  • I'm doing the rotation right now. And I'm setting the offset to the center of the image so that the group rotates about its center. but it is not working. Why in your code, you need to divide the scalePT by the scaleFactor? and if I'm rotating, does that mean that I need to introduce the angle of rotation to compute the offset? – user1499220 Aug 05 '13 at 20:52
  • ScalePt/scaleFactor is undoing the previous scale transform and undoing the previous offset in preparation for a new transform. And about other transforms--rotation for example, you're correct. Whether you scale, rotate and/or translate, the process always reduces to: Undo, then CalculateNew, then ApplyNew. Also transformation order is important too. If you rotate+scale then you would unscale, unrotate, CalculateNew, applyNewRotate, applyNewScale. – markE Aug 05 '13 at 21:56
  • thank you for your answer @markE. My question is how do you know which values to give to the offset? For the zoom you did : offset= offset - scalePt/scaleFactor. For the rotation, do I need to do offset= offset - scalePt/angle ? I understood the concept of undoing -recalculate .. but still don't understand how you choose the values of the offset. – user1499220 Aug 05 '13 at 22:15
  • I read in your comment that you're willing to have your groups registration point be its centerpoint. This allows much simpler code. I have replace my original answer with the simpler code (no complicated "state management" required now). – markE Aug 06 '13 at 06:21