如何在画布中旋转对象

时间:2018-02-02 11:14:07

标签: javascript canvas

我试图仅在画布中旋转一个对象,而不是整个画布。

我的代码如下:



var canvas = document.getElementById('canvas');
var buttons = document.getElementById('buttons');
var img = document.getElementById('photo');
var ctx = canvas.getContext('2d');
var rect = {};
var drag = false;
var buttons_shown = false;
var angle = 10;
var rotate_angle = 0;


var original_source = img.src;
img.src = original_source;

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);
        document.addEventListener("keydown", keyDownPressed, false);
    });


}

function keyDownPressed(e) {
    var keyCode = e.keyCode;
    var left_arrow = 37;
    var right_arrow = 39;
    var up_arrow = 38;
    var down_arrow = 40;

    if(keyCode === left_arrow) {
        onRotateLeft()
    }

    if(keyCode === right_arrow){
        onRotateRight()
    }
}

function mouseDown(e) {
    rect.startX = e.offsetX;
    rect.startY = e.offsetY;
    drag = true;
    buttons_shown = false;
    buttons.classList.add("hide");
}

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

function onRemoveSelectionClick(e) {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    drag = false;
    buttons_shown = false;
    buttons.classList.add("hide");
}

function onRotateLeft(){
    rotate_angle = rotate_angle - angle;
    canvas.style.transform = 'rotate(' + rotate_angle + 'deg)';    
}

function onRotateRight(){
    rotate_angle = rotate_angle + angle;
    canvas.style.transform = 'rotate(' + rotate_angle + 'deg)';
}

function mouseMove(e) {
    if (drag) {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        rect.w = (e.pageX - this.offsetLeft) - rect.startX;
        rect.h = (e.pageY - this.offsetTop) - rect.startY;
        ctx.shadowBlur = 5;
        ctx.filter = 'blur(10px)';
        ctx.fillRect(rect.startX, rect.startY, rect.w, rect.h);
        ctx.strokeRect(rect.startX, rect.startY, rect.w, rect.h);

    }else{
        if(buttons_shown && buttons.classList.contains("hide")){
            buttons.classList.remove("hide");
        }
    }
}
//
init();

.hide{
    display: none !important;
}

canvas{
  position: absolute;
  left: 0; 
  right: 0; 
  top: 0; 
  bottom: 0; 
  display:inline-block;
  background-color: yellow;
}

<div style="position: relative; overflow: hidden;display:inline-block;">
    <img id="photo" src="http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg"/>
    <canvas id="canvas"></canvas>
</div>


<div id="buttons" class="hide">
    <button onclick="onRotateLeft()">Rotate Left</button>
    <button onclick="onRotateRight()">Rotate right</button><br />
    <button onclick="onRemoveSelectionClick()">Remove Selection</button>
</div>
&#13;
&#13;
&#13;

因此,如果绘制了一个对象,我会显示按钮向左或向右旋转或删除它。如果我单击例如Rotate Left按钮,它将执行下一个代码:

rotate_angle = rotate_angle - angle;
canvas.style.transform = 'rotate(' + rotate_angle + 'deg)';

但是这会旋转我的整个画布(黄色背景),但我想只旋转画布内的对象。

有什么想法吗?

2 个答案:

答案 0 :(得分:1)

使用画布变换而非CSS变换。

渲染矩形时,需要在画布中应用变换。

该代码段是代码的副本,但有一些更改。

  • 渲染是通过requestAnimationFrame完成的,以便在鼠标移动时不会有不必要的渲染。

  • 只要需要更新画布,全局标记update就会设置为true

  • rectangles数组用于存储每个矩形。

  • 矩形对象还存储其旋转rect.rotate,以便每个矩形都有一个独立的旋转。

  • 全局变量rect包含当前矩形。

  • 事件更改全局rect对象并设置update = true标志,它们不进行任何渲染。

  • 矩形围绕其中心旋转

  • Canvas context ctx.rotate使用的弧度不是度

有关详细信息,请参阅代码。

&#13;
&#13;
var canvas = document.getElementById('canvas');
var buttons = document.getElementById('buttons');
var img = document.getElementById('photo');
var ctx = canvas.getContext('2d');
var rect = {};
var drag = false;
var buttons_shown = false;
var angle = 10 * (Math.PI / 180) ;
var rotate_angle = 0;

var update = true; // when true updates canvas


var original_source = img.src;
img.src = original_source;

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);
        document.addEventListener("keydown", keyDownPressed, 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);
}

// array of rectangles
const rectangles = [];

// adds a rectangle
function addRectangle(rect){
   rectangles.push(rect);
   
}

// draws a rectangle with rotation 
function drawRect(rect){
   ctx.setTransform(1,0,0,1,rect.startX + rect.w / 2, rect.startY + rect.h / 2);
   ctx.rotate(rect.rotate);
   ctx.beginPath();
   ctx.rect(-rect.w/2, -rect.h/2, rect.w, rect.h);
   ctx.fill();
   ctx.stroke();


}

// clears canvas sets filters and draws rectangles
function drawCanvas(){
    // restore the default transform as rectangle rendering does not restore the transform.
    ctx.setTransform(1,0,0,1,0,0);
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.shadowBlur = 5;
    ctx.filter = 'blur(10px)';
    rectangles.forEach(drawRect);


}

function keyDownPressed(e) {
    var keyCode = e.keyCode;
    var left_arrow = 37;
    var right_arrow = 39;
    var up_arrow = 38;
    var down_arrow = 40;

    if(keyCode === left_arrow) {
        onRotateLeft()
    }

    if(keyCode === right_arrow){
        onRotateRight()
    }
}

// create new rect add to array 
function mouseDown(e) {
    rect = {
      startX : e.offsetX,
      startY : e.offsetY,
      w : 1,
      h : 1,
      rotate : 0,
    };
    drag = true;
    buttons_shown = false;
    buttons.classList.add("hide");
    addRectangle(rect);
    update = true;
}

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


// removes top rectangle and sets next down as current or if none then hides controls
function onRemoveSelectionClick(e) {

    rectangles.pop();
    if(rectangles.length === 0){
      drag = false;
      buttons_shown = false;
      buttons.classList.add("hide");
    }else{
      rect = rectangles[rectangles.length -1];
    }
    update = true;
}

// rotate current rectangle
function onRotateLeft(){
    rect.rotate -= angle;
    update = true;
      
}

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

function mouseMove(e) {
    if (drag) {
        rect.w = (e.pageX - this.offsetLeft) - rect.startX;
        rect.h = (e.pageY - this.offsetTop) - rect.startY;
        update = true;

    }else{
        if(buttons_shown && buttons.classList.contains("hide")){
            buttons.classList.remove("hide");
        }
    }
}
//
init();
&#13;
.hide{
    display: none !important;
}

canvas{
  position: absolute;
  left: 0; 
  right: 0; 
  top: 0; 
  bottom: 0; 
  display:inline-block;
  background-color: yellow;
}
&#13;
<div style="position: relative; overflow: hidden;display:inline-block;">
    <img id="photo" src="http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg"/>
    <canvas id="canvas"></canvas>
</div>


<div id="buttons" class="hide">
    <button onclick="onRotateLeft()">Rotate Left</button>
    <button onclick="onRotateRight()">Rotate right</button><br />
    <button onclick="onRemoveSelectionClick()">Remove Selection</button>
</div>
&#13;
&#13;
&#13;

答案 1 :(得分:0)

对象需要一个单独的画布;在这个单独的画布上绘制对象然后,根据您实际打算做什么,您可以:

  • 使用context.rotate()结合context.drawImage();
  • 在主要内容上绘制辅助画布的内容
  • 使用CSS将一个画布叠加在另一个画布上。

然后,也许您可​​以使用context.rotate()然后在主画布上绘制,如下所示:HTML5 Canvas Rotate Image