0

I am trying to make an image object rotate in accordance to the mouse being clicked down on that image and the angle of the mouse to the center of the object.

Think of a unit circle and having the image being rotated about the circle based on where the mouse is on that circle.

I currently have

var stage = new Kinetic.Stage({
container: "container",
width: 800,
height: 500,
id: "myCanvas",
name: "myCanvas"
});
var layer = new Kinetic.Layer();
//gets the canvas context
var canvas = stage.getContainer();
var mousePosX;
var mousePosY;
var mouseStartAngle;
var selectedImage;
var mouseAngle;
var mouseStartAngle;
console.log(canvas)

var shiftPressed
window.addEventListener('keydown', function (e) {
if (e.keyCode == "16") {
    shiftPressed = true;
}
console.log(shiftPressed)
}, true);

window.addEventListener('keyup', function (e) {
if (e.keyCode == "16") {
    shiftPressed = false;
}
console.log(shiftPressed)
}, true);

function drawImage(imageObj) {

var dynamicImg = new Kinetic.Image({
    image: imageObj,
    x: stage.getWidth() / 2 - 200 / 2,
    y: stage.getHeight() / 2 - 137 / 2,
    width: 100, //imageObj.width,
    height: 100, // imageObj.height,
    draggable: true,
    offset: [50,50] //[(imageObj.width/2), (imageObj.height/2)]

});

dynamicImg.on('mousedown', function () {


    selectedImage = this;
    console.log("x: " + this.getX())
    console.log("y: " + this.getY())

    var mouseStartXFromCenter = mousePosX - (this.getX() + (this.getWidth() / 2));
    var mouseStartYFromCenter = mousePosY - (this.getY() + (this.getHeight() / 2));
    mouseStartAngle = Math.atan2(mouseStartYFromCenter, mouseStartXFromCenter);

    if (shiftPressed) {
        //console.log("trying to switch draggable to false");
        //console.log(this)
        this.setDraggable(false);
    }
});

dynamicImg.on('mouseup mouseout', function () {
    //console.log('mouseup mouseout')
    this.setDraggable(true);
});


dynamicImg.on('mouseover', function () {
    document.body.style.cursor = 'pointer';
});
dynamicImg.on('mouseout', function () {
    document.body.style.cursor = 'default';
});

imageArray.push(dynamicImg);
layer.add(dynamicImg);
stage.add(layer);
}
var imageObj = new Image();
imageObj.onload = function () {
drawImage(this);

};
imageObj.src = 'http://localhost:60145/Images/orderedList8.png';

function getMousePos(evt) {

var rect = canvas.getBoundingClientRect();
return {
    x: evt.clientX - rect.left,
    y: evt.clientY - rect.top
};
}


canvas.addEventListener('mouseup', function () {
selectedImage = undefined;
});

canvas.addEventListener('mousemove', function (evt) {
mousePos = getMousePos(evt);
//console.log('Mouse position: ' + mousePos.x + ',' + mousePos.y)
mousePosX = mousePos.x;
mousePosY = mousePos.y;

if (selectedImage != undefined) {

    mouseXFromCenter = mousePosX - selectedImage.getX();
    mouseYFromCenter = mousePosY - selectedImage.getY();
    mouseAngle = Math.atan2(mouseYFromCenter, mouseXFromCenter);

    var rotateAngle = mouseAngle - mouseStartAngle;

    selectedImage.setRotation(rotateAngle);

}
}, false);

the code has a couple things to it. -It should only allow a rotate if 'shift' is pressed and mousedown event happens on an image.

-it needs to maintain the dynamic image drawing as they will be populating the canvas dynamically over the life of the page.

here is a good example of something similar i want to happen, but just simply cannot get it to work in canvas/kineticjs. http://jsfiddle.net/22Feh/5/

kevindstanley
  • 15
  • 1
  • 3

3 Answers3

1

I would go simpler way using dragBoundFunc. http://jsfiddle.net/bighostkim/vqGmL/

dragBoundFunc: function (pos, evt) {
    if (evt.shiftKey) {
        var x = this.getX() - pos.x;
        var y = this.getY() - pos.y;
        var radian = Math.PI + Math.atan(y/x);
        this.setRotation(radian);
        return {
            x: this.getX(),
            y: this.getY()
        }
     } else {
        return pos;
     }
}
allenhwkim
  • 27,270
  • 18
  • 89
  • 122
0

You should be more clear what your .on() events do. In your code, the mousedown on the shape doesn't do anything other than calculate an mouseStartAngle, but doesn't do anything. And your mouseUp on the shape event doesn't do much either. It's your browser/client mousedown/mouseup that do all the work, and that's why it rotates properly on some clicks and not others.

For setting the rotation you have many options, here are two:

Option one: set the radians manually on mousedown

  dynamicImg.on('mousedown', function () {   
    dynamicImg.setRotation(mouseStartAngle); //set the rotation degree
    layer.draw(); // redraw the layer
  }

Option two: let kineticJS animate the rotation for you

  dynamicImg.on('mousedown', function () { 
    dynamicImg.transitionTo({  
        duration: 1,       // length of animation in seconds
        rotation: mouseStartAngle   // your angle, in radians
    });
  }

your updated jsfiddle: http://jsfiddle.net/WXHe6/1/

Here are some additional notes:

The reason you are having trouble is because your code is structured is a bit of a messy manner, sorry to say. You are mixing browser events with and adding listeners to the canvas rather than using built-in kineticJS functionality, for example, you could use stage.getUserPosition() to get the mouse coordinates. Unless you have some dire need to structure your project this way, try to avoid it.

What I do like is that you have created functions to break up your code, but on the down-side you have multiple functions doing the same thing, like calculating and updating the rotation angle. Why not just make one function to get the angle?

Some Tips:

  1. Try using mainly KineticJS for functionality (I know you'll need event listeners for buttons like SHIFT). What I mean is, use things like stage.getUserPosition(); to get the mouse/touch coordinates, rather than evt.clientX, it's cleaner, and the work has been done for you already, no need to re-invent the wheel.

  2. Make one function for setting/getting the rotation for a shape. Then you can call it whenever you want. (use less repetitive code)

  3. If you don't want the shape to be draggable when shift is clicked, you should set that before an item is clicked. You have button listeners so you can either disable rotation for all shapes when shift is pressed down, or just for a shape on that is under the cursor.

  4. imageArray.push(dynamicImg); not sure if you really need this, if you need to access all the elements as an array, you could alway do layer.getChildren(); to get all the images in the layer, or access them numerically like layer.getChildren()[0]; (in creation order)

SoluableNonagon
  • 11,541
  • 11
  • 53
  • 98
0

My mistake, I misread your question. You were essentially missing one line:

    layer.draw();

Hold shift and move the mouse, you'll see it rotates nicely. http://jsfiddle.net/WXHe6/2/

    canvas.addEventListener('mousemove', function (evt) {
            mousePos = getMousePos(evt);
            //console.log('Mouse position: ' + mousePos.x + ',' + mousePos.y)
            mousePosX = mousePos.x;
            mousePosY = mousePos.y;

            if (selectedImage != undefined) {

            mouseXFromCenter = mousePosX - selectedImage.getX();
            mouseYFromCenter = mousePosY - selectedImage.getY();
            mouseAngle = Math.atan2(mouseYFromCenter, mouseXFromCenter);

            var rotateAngle = mouseAngle - mouseStartAngle;

            selectedImage.setRotation(rotateAngle);
            layer.draw(); // <--------------- right here
  }
  }, false);
SoluableNonagon
  • 11,541
  • 11
  • 53
  • 98