如何检测鼠标是否沿顺时针方向移动

时间:2018-03-07 08:28:17

标签: javascript canvas rotation html5-canvas

我想在鼠标移动时在画布上旋转一个形状,我想检测鼠标是否在clockwise direction移动,但我不知道该怎么做。这是我的代码:



var canvas = document.getElementById('canvas');
var img = document.getElementById('photo');
var ctx = canvas.getContext('2d');

var annotation_rect = canvas.getBoundingClientRect();
rect = {
      startX : 150,
      startY : 50,
      w : 250,
      h : 150,
      endX : 0,
      endY : 0,
      rotate: 0
    };
var drag = false;
var rotating = false;
var update = true; // when true updates canvas
var rotate_angle = 5; // in degrees - for rotating blurred part
var angle = rotate_angle * (Math.PI / 180);
var original_source = img.src;
img.src = original_source;

function rotateRight(){
	rect.rotate += angle;
  update = true;
}

function rotateLeft(){
	rect.rotate -= angle;
  update = true;
}

function init() {
    img.addEventListener('load', function(){
        canvas.width = img.width;
        canvas.height = img.height;
        canvas.addEventListener('mousedown', mouseDown, false);
        canvas.addEventListener('mouseup', mouseUp, false);
        canvas.addEventListener('mousemove', mouseMove, false);
    });
    
    // start the rendering loop
    requestAnimationFrame(updateCanvas);
}

// main render loop only updates if update is true
function updateCanvas(){
  if(update){
      drawCanvas();
      update = false;
  }

  requestAnimationFrame(updateCanvas);
}

// draws a rectangle with rotation 
function drawRect(){
		ctx.setTransform(1,0,0,1,rect.startX + rect.w / 2, rect.startY + rect.h / 2);
    ctx.rotate(rect.rotate);
    ctx.beginPath();
    ctx.shadowBlur = 5;
    ctx.filter = 'blur(10px)';
    ctx.rect(-rect.w/2, -rect.h/2, rect.w, rect.h);
    ctx.lineWidth = 3;
    ctx.strokeStyle = "#fff";
    ctx.fillStyle = "#fff";
    ctx.fill();
    ctx.stroke();
}

// clears canvas sets filters and draws rectangles
function drawCanvas(){    
		ctx.setTransform(1,0,0,1,0,0);
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = 'rgba(0, 0, 0, 0.6)';
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    drawRect()
}

// create new rect add to array 
function mouseDown(e) {
    drag = true;
}

function mouseUp() { drag = false; update = true; }



function startRotation(e){
    rotating = true;
}

function stopRotation(e){
    rotating = false;
}

function onShapeRotating(e){
    if(rotating){
         rotateRight();
    }
} 



function mouseMove(e) {
		var mouseX = e.offsetX - annotation_rect.left,
    		mouseY = e.offsetY - annotation_rect.top,
        endX = rect.startX + rect.w,
    		endY = rect.startY + rect.h
    
		var cursorOnShape = mouseX >= rect.startX && mouseX <= endX && mouseY >= rect.startY && mouseY <= endY;
    
    
    if(cursorOnShape){
        canvas.style.cursor = "pointer"
        
        canvas.addEventListener('mousedown', startRotation, false);
        canvas.addEventListener('mouseup', stopRotation, false);
        canvas.addEventListener('mousemove', onShapeRotating, false);
    }else{    
        canvas.style.cursor = "default"
        canvas.removeEventListener('mousedown', startRotation, false);
        canvas.removeEventListener('mouseup', stopRotation, false);
        canvas.removeEventListener('mousemove', onShapeRotating, false);
    }
}

init();
&#13;
canvas{
  position: absolute;
  left: 0; 
  right: 0; 
  top: 0; 
  bottom: 0; 
  display:inline-block;
  background:rgba(0,0,0,0.3);
}
&#13;
<div style="position: relative; overflow: hidden;display:inline-block;">
    <img id="photo" src="https://carsales.pxcrush.net/carsales/car/cil/cc5166737225893351785.jpg?width=600&height=300&overlay&aspect=FitWithIn&watermark=1439104668"/>
    <canvas id="canvas"></canvas>
</div>
&#13;
&#13;
&#13;

因此我在画布上画了一个矩形,我检测到鼠标是否在那个矩形上,如果是,我调用函数rotateShape并在那里调用函数rotateRight。这是有效的。如果您使用鼠标在矩形上并按下它并旋转它将旋转调用函数rotateRight的矩形。

但我希望能够检查鼠标是否顺时针方向移动。如果它按顺时针方向移动,我会拨打rotateRight,如果没有,那么我会拨打rotateLeft

知道怎么做吗?

Here is the fiddle.

3 个答案:

答案 0 :(得分:1)

不是按固定值旋转,而是按最后已知角度和新角度之间的差值旋转。

要获得这些角度,您可以使用

var angle = Math.atan2(
  e.clientY - (rect.startY + rect.h /2),
  e.clientX - (rect.startX + rect.w /2)
);

var canvas = document.getElementById('canvas');
var img = document.getElementById('photo');
var ctx = canvas.getContext('2d');

var annotation_rect = canvas.getBoundingClientRect();
rect = {
  startX: 150,
  startY: 50,
  w: 250,
  h: 150,
  endX: 0,
  endY: 0,
  rotate: 0
};
var drag = false;
var rotating = false;
var update = true; // when true updates canvas
var original_source = img.src;
img.src = original_source;

// keep track of the last angle
var prevAngle = null;
// a single function
function rotate(angle) {
  rect.rotate += angle;
  update = true;
}
// called on mousemove when dragging
function onShapeRotating(e) {
  if (rotating) {
    var angle = Math.atan2(
      e.clientY - (rect.startY + rect.h / 2),
      e.clientX - (rect.startX + rect.w / 2)
    );
    if (prevAngle !== null)
      rotate(angle - prevAngle)
    prevAngle = angle;
  }
}

function init() {
  img.addEventListener('load', function() {
    canvas.width = img.width;
    canvas.height = img.height;
    canvas.addEventListener('mousedown', mouseDown, false);
    canvas.addEventListener('mouseup', mouseUp, false);
    canvas.addEventListener('mousemove', mouseMove, false);
  });

  // start the rendering loop
  requestAnimationFrame(updateCanvas);
}

// main render loop only updates if update is true
function updateCanvas() {
  if (update) {
    drawCanvas();
    update = false;
  }

  requestAnimationFrame(updateCanvas);
}

// draws a rectangle with rotation 
function drawRect() {
  ctx.setTransform(1, 0, 0, 1, rect.startX + rect.w / 2, rect.startY + rect.h / 2);
  ctx.rotate(rect.rotate);
  ctx.beginPath();
  ctx.shadowBlur = 5;
  ctx.filter = 'blur(10px)';
  ctx.rect(-rect.w / 2, -rect.h / 2, rect.w, rect.h);
  ctx.lineWidth = 3;
  ctx.strokeStyle = "#fff";
  ctx.fillStyle = "#fff";
  ctx.fill();
  ctx.stroke();
}

// clears canvas sets filters and draws rectangles
function drawCanvas() {
  ctx.setTransform(1, 0, 0, 1, 0, 0);
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.fillStyle = 'rgba(0, 0, 0, 0.6)';
  ctx.fillRect(0, 0, canvas.width, canvas.height);
  drawRect()
}

// create new rect add to array 
function mouseDown(e) {
  drag = true;
}

function mouseUp() {
  prevAngle = null;
  drag = false;
  update = true;
}



function startRotation(e) {
  rotating = true;
}

function stopRotation(e) {
  rotating = false;
}


function mouseMove(e) {
  var mouseX = e.offsetX - annotation_rect.left,
    mouseY = e.offsetY - annotation_rect.top,
    endX = rect.startX + rect.w,
    endY = rect.startY + rect.h

  var cursorOnShape = mouseX >= rect.startX && mouseX <= endX && mouseY >= rect.startY && mouseY <= endY;


  if (cursorOnShape) {
    canvas.style.cursor = "pointer"

    canvas.addEventListener('mousedown', startRotation, false);
    canvas.addEventListener('mouseup', stopRotation, false);
    canvas.addEventListener('mousemove', onShapeRotating, false);
  } else {
    canvas.style.cursor = "default"
    canvas.removeEventListener('mousedown', startRotation, false);
    canvas.removeEventListener('mouseup', stopRotation, false);
    canvas.removeEventListener('mousemove', onShapeRotating, false);
  }
}

init();
canvas {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  display: inline-block;
  background: rgba(0, 0, 0, 0.3);
}
<div style="position: relative; overflow: hidden;display:inline-block;">
  <img id="photo" src="https://carsales.pxcrush.net/carsales/car/cil/cc5166737225893351785.jpg?width=600&height=300&overlay&aspect=FitWithIn&watermark=1439104668" />
  <canvas id="canvas"></canvas>
</div>

现在,您的代码有很多东西需要修复,但我会告诉您。

你最好在整个画布/文档上放置单个事件,而不是有选择地添加一个事件 您的cursorOnShape算法没有考虑矩形的旋转。

答案 1 :(得分:0)

好的,这不是合适的方式,对不起:

var canvas = document.getElementById('canvas');
var img = document.getElementById('photo');
var ctx = canvas.getContext('2d');

var annotation_rect = canvas.getBoundingClientRect();
rect = {
      startX : 150,
      startY : 50,
      w : 250,
      h : 150,
      endX : 0,
      endY : 0,
      rotate: 0
    };
var drag = false;
var rotating = false;
var update = true; // when true updates canvas
var rotate_angle = 5; // in degrees - for rotating blurred part
var angle = rotate_angle * (Math.PI / 180);
var original_source = img.src;
var bLeft = true;
img.src = original_source;

function rotateRight(){
	rect.rotate += angle;
  update = true;
}

function rotateLeft(){
	rect.rotate -= angle;
  update = true;
}

function init() {
    img.addEventListener('load', function(){
        canvas.width = img.width;
        canvas.height = img.height;
        canvas.addEventListener('mousedown', mouseDown, false);
        canvas.addEventListener('mouseup', mouseUp, false);
        canvas.addEventListener('mousemove', mouseMove, false);
    });
    
    // start the rendering loop
    requestAnimationFrame(updateCanvas);
}

// main render loop only updates if update is true
function updateCanvas(){
  if(update){
      drawCanvas();
      update = false;
  }

  requestAnimationFrame(updateCanvas);
}

// draws a rectangle with rotation 
function drawRect(){
		ctx.setTransform(1,0,0,1,rect.startX + rect.w / 2, rect.startY + rect.h / 2);
    ctx.rotate(rect.rotate);
    ctx.beginPath();
    ctx.shadowBlur = 5;
    ctx.filter = 'blur(10px)';
    ctx.rect(-rect.w/2, -rect.h/2, rect.w, rect.h);
    ctx.lineWidth = 3;
    ctx.strokeStyle = "#fff";
    ctx.fillStyle = "#fff";
    ctx.fill();
    ctx.stroke();
}

// clears canvas sets filters and draws rectangles
function drawCanvas(){    
		ctx.setTransform(1,0,0,1,0,0);
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = 'rgba(0, 0, 0, 0.6)';
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    drawRect()
}

// create new rect add to array 
function mouseDown(e) {
    drag = true;
}

function mouseUp() { drag = false; update = true; }



function startRotation(e){
    rotating = true;
}

function stopRotation(e){
    rotating = false;
}

function onShapeRotating(e){
    if(rotating && !bLeft){
         rotateRight();
    } else if(rotating && bLeft){
         rotateLeft();
    }
} 



function mouseMove(e) {
		var mouseX = e.offsetX - annotation_rect.left,
    		mouseY = e.offsetY - annotation_rect.top,
        endX = rect.startX + rect.w,
    		endY = rect.startY + rect.h
    
		var cursorOnShape = mouseX >= rect.startX && mouseX <= endX && mouseY >= rect.startY && mouseY <= endY;
    
    bLeft = ( rect.startX + rect.w/2 - mouseX ) > 0 ? true:false;
    if(cursorOnShape){
        canvas.style.cursor = "pointer"
        
        canvas.addEventListener('mousedown', startRotation, false);
        canvas.addEventListener('mouseup', stopRotation, false);
        canvas.addEventListener('mousemove', onShapeRotating, false);
    }else{    
        canvas.style.cursor = "default"
        canvas.removeEventListener('mousedown', startRotation, false);
        canvas.removeEventListener('mouseup', stopRotation, false);
        canvas.removeEventListener('mousemove', onShapeRotating, false);
    }
}

init();
canvas{
  position: absolute;
  left: 0; 
  right: 0; 
  top: 0; 
  bottom: 0; 
  display:inline-block;
  background:rgba(0,0,0,0.3);
}
<div style="position: relative; overflow: hidden;display:inline-block;">
    <img id="photo" src="https://carsales.pxcrush.net/carsales/car/cil/cc5166737225893351785.jpg?width=600&height=300&overlay&aspect=FitWithIn&watermark=1439104668"/>
    <canvas id="canvas"></canvas>
</div>

答案 2 :(得分:0)

计算角度变化

使用Math.atan2()的问题是Math.atan2(1,-10)Math.atan2(-1,-10)之间的差异是6.084而不是0.199,这意味着当您累积差异的总和时,您永远不会得到超过{{的值1}}或Math.PI

换句话说,你不能直接跟踪你已经完成的转弯次数,也不知道你是顺时针还是逆时针转动。

交叉产品

计算鼠标围绕某个点旋转的方向和数量的最佳方法是使用从中心到鼠标位置和旧位置的两个向量的叉积

-Math.PI

如果逆时针方向,该功能将返回负角度,如果是顺时针方向,则返回正方向。

实施例

示例显示上述函数用于跟踪总旋转,而不是其他答案的绝对方向。

// cx,cy center of rotation
// ox,oy old position of mouse
// mx,my new position of mouse.
function getAngle(cx, cy, ox, oy, mx, my){
    var x1 = ox - cx;
    var y1 = oy - cy;
    var x2 = mx - cx;
    var y2 = my - cy;
    var d1 = Math.sqrt(x1 * x1 + y1 * y1);
    var d2 = Math.sqrt(x2 * x2 + y2 * y2);

    return Math.asin((x1 / d1) * (y2 / d2) - (y1 / d1) * (x2 / d2));
}
const mouse  = {x : 0, y : 0, ox : 0, oy : 0, down : false};
["down","up","move"].forEach(name => document.addEventListener("mouse" + name,mouseEvents));
const ctx = canvas.getContext("2d");

function mouseEvents(e) {
  mouse.x = e.pageX; mouse.y = e.pageY;
  mouse.down = e.type === "mousedown" ? true : e.type === "mouseup" ? false : mouse.down;
}

function getAngleBetween(cx, cy, ox, oy, mx, my) {
  var x1 = ox - cx;
  var y1 = oy - cy;
  var x2 = mx - cx;
  var y2 = my - cy;
  // max to prevent div by zero
  var d1 = Math.max(0.001, Math.sqrt(x1 * x1 + y1 * y1));
  var d2 = Math.max(0.001, Math.sqrt(x2 * x2 + y2 * y2));
  return Math.asin((x1 / d1) * (y2 / d2) - (y1 / d1) * (x2 / d2));
}
var w, h, cw, ch;
var angle = 0;
function update() {
  ctx.setTransform(1, 0, 0, 1, 0, 0); // reset transform
  if (w !== innerWidth || h !== innerHeight) {
    cw = (w = canvas.width = innerWidth) / 2;
    ch = (h = canvas.height = innerHeight) / 2;
  } else {
    ctx.clearRect(0, 0, w, h);
  }
  var change = 0;
  if (mouse.down) {
    change = getAngleBetween(cw, ch, mouse.ox, mouse.oy, mouse.x, mouse.y);
    angle += change;
  }

  ctx.setTransform(1, 0, 0, 1, cw, ch);
  ctx.rotate(angle);
  ctx.fillRect(-100, -25, 200, 50);


  ctx.setTransform(1, 0, 0, 1, 0, 0);
  ctx.font = "28px arial";
  ctx.textAlign = "center";
  ctx.fillText("Total rotation : " + ((angle * 180 / Math.PI) | 0), cw, 30);
  ctx.font = "14px arial";
  ctx.fillText("Change : " + (change * 180 / Math.PI).toFixed(2), cw, 48);

  ctx.fillText("Click drag to rotate box.", cw, h - 20);

  mouse.ox = mouse.x;
  mouse.oy = mouse.y
  requestAnimationFrame(update);
}
requestAnimationFrame(update);
canvas {
  position: absolute;
  top: 0px;
  left: 0px;
}