在旋转的CANVAS上绘制

时间:2016-09-23 22:17:51

标签: javascript html5 canvas html5-canvas

我有一个canvas我可以用鼠标画画。

在某些时候,我可以旋转和缩放画布容器。

我想要的是能够仍然绘制,但我现在遇到的问题是旋转和缩放鼠标坐标。

取消旋转取消缩放鼠标坐标的正确方法是什么,以便从用户的角度正常渲染新图纸?

我已尝试将X坐标转换为Y,但无法使数学正确。

CODE& FIDDLE

HTML

<div id="canvasDiv">
  <canvas id="canvas"></canvas>
</div>

<button>Rotate & Scale</button>

CSS

div
{
    outline: 1px solid red;
    text-align: center;
    width: 250px;
    height: 250px;
    position: relative;
}
canvas
{
    outline: 1px solid blue;
    width: 250px;
    height: 250px;
    bottom: 0;
    left: 0;
    position: absolute;
    right: 0;
    top: 0;
    z-index: 5;
}

.transformed
{
    transform: rotate(90deg) scale(1.4);
    margin-top: 75px;
    margin-left: 75px;
}

JS

isMouseDown = false;
canvas_offset = {left: 0, top: 0};
mouse = {x1: 0, y1: 0, x2: 0, y2: 0};
ppts = [];

canvas = $('#canvas').get(0);
ctx = canvas.getContext('2d');

canvas_container = $('#canvasDiv').get(0);
canvas_container_style = getComputedStyle(canvas_container);
canvas.width = parseInt(canvas_container_style.getPropertyValue('width'));
canvas.height = parseInt(canvas_container_style.getPropertyValue('height'));

var offset = $('#canvas').offset();
canvas_offset.left = offset.left;
canvas_offset.top = offset.top;

// Creating a tmp canvas
tmp_canvas = document.createElement('canvas');
tmp_ctx = tmp_canvas.getContext('2d');
tmp_canvas.id = 'tmp_canvas';
tmp_canvas.width = canvas.width;
tmp_canvas.height = canvas.height;

tmp_canvas.area = tmp_canvas.getBoundingClientRect();

canvas_container.appendChild(tmp_canvas);

$(document).on("mousedown", tmp_canvas, function(e)
{
    mouse.x1 = parseInt(e.clientX - tmp_canvas.area.left);
    mouse.y1 = parseInt((e.clientY - tmp_canvas.area.top - canvas_offset.top) + $(document).scrollTop());

    ppts.push({
            x: mouse.x1,
            y: mouse.y1,
            size: 1,
            color: "#000000"
    });

  isMouseDown = true;
});

$(document).on("mouseup", tmp_canvas, function(e)
{
    isMouseDown = false;

    ctx.drawImage(tmp_canvas, 0, 0);
    tmp_ctx.clearRect(0, 0, tmp_canvas.width, tmp_canvas.height);

    ppts = [];
});

$(document).on("mousemove", tmp_canvas, function(e)
{
    mouse.x2 = parseInt(e.clientX - tmp_canvas.area.left);
    mouse.y2 = parseInt((e.clientY - tmp_canvas.area.top - canvas_offset.top) + $(document).scrollTop());

    if(isMouseDown)
    {
        onPaint();
  }
});

var onPaint = function()
{
    // Saving all the points in an array
    ppts.push({
        x: mouse.x2,
        y: mouse.y2,
        size: 1,
        color: "#000000"
    });

    if(ppts.length < 3)
    {
        var b = ppts[0];
        tmp_ctx.beginPath();
        //ctx.moveTo(b.x, b.y);
        //ctx.lineTo(b.x+50, b.y+50);
        tmp_ctx.arc(b.x, b.y, tmp_ctx.lineWidth / 2, 0, Math.PI * 2, !0);
        tmp_ctx.fill();
        tmp_ctx.closePath();

        return;
    }

    // Tmp canvas is always cleared up before drawing.
    tmp_ctx.clearRect(0, 0, tmp_canvas.width, tmp_canvas.height);

    tmp_ctx.beginPath();
    tmp_ctx.moveTo(ppts[0].x, ppts[0].y);

    for(var i = 1; i < ppts.length - 2; i++)
    {
        var c = (ppts[i].x + ppts[i + 1].x) / 2;
        var d = (ppts[i].y + ppts[i + 1].y) / 2;

        tmp_ctx.lineWidth = ppts[i].size;
        tmp_ctx.strokeStyle = ppts[i].color;

        tmp_ctx.quadraticCurveTo(ppts[i].x, ppts[i].y, c, d);
    }

    // For the last 2 points
    tmp_ctx.quadraticCurveTo(
        ppts[i].x,
        ppts[i].y,
        ppts[i + 1].x,
        ppts[i + 1].y
    );

    tmp_ctx.stroke();
};

$("button").click(function()
{
    $("div").addClass("transformed");
});

FIDDLE https://jsfiddle.net/h0cuycp4/

1 个答案:

答案 0 :(得分:0)

最后我有这个工作!!

所有信用都转到Blindman67,我修改了他的代码以使其适应我的需求。

HTML

<div id="main"></div>
<br>
<span id="screen" style="border: 2px solid red;"></span>
<span id="world" style="border: 2px solid blue;"></span>
<button id="btnRotate">ROTATE!</button>

JS

var canvas = null;
var ctx = null;
var gridStart = null;
var gridEnd = null;
var gridStepMajor = null;
var gridStepMinor = null;
var minorCol = null;
var majorCol = null;
var minorWidth = null;
var majorWidth = null;

var scale = 1;
var rotation = 45;

    var painting = false,
    lastX = 0,
    lastY = 0,
    lineThickness = 1;

var matrix = [1, 0, 0, 1, 0, 0];      // normal matrix
var invMatrix = [1, 0, 0, 1];   // inverse matrix

function createMatrix(x, y, scale, rotation)
{
    rotation = rotation * (Math.PI / 180);

    var m = matrix; // just to make it easier to type and read
    var im = invMatrix; // just to make it easier to type and read

    // create the scale and rotation part of the matrix
    m[3] =   m[0] = Math.cos(rotation) * scale;
    m[2] = -(m[1] = Math.sin(rotation) * scale);

    // translation
    m[4] = x;
    m[5] = y;

    // calculate the inverse transformation
    // first get the cross product of x axis and y axis
    cross = m[0] * m[3] - m[1] * m[2];

    // now get the inverted axies
    im[0] =  m[3] / cross;
    im[1] = -m[1] / cross;
    im[2] = -m[2] / cross;
    im[3] =  m[0] / cross;
}

// function to transform to world space
function toWorld(x,y)
{
    var xx, yy, m;
    m = invMatrix;
    xx = x - matrix[4];
    yy = y - matrix[5];
    return{
       x:   parseInt(xx * m[0] + yy * m[2], 10) ,
       y:   parseInt(xx * m[1] + yy * m[3], 10)
    }
}
//----------------------------------------------------------------------------
var mouseWorldPos = toWorld(0, 0);

function draw()
{
    gridStart = 0;
    gridEnd = canvas.width;
    gridStepMajor = canvas.width / 10;
    gridStepMinor = canvas.width / 20;
    minorCol = "#999";
    majorCol = "#000";
    minorWidth = 1;
    majorWidth = 3;

    ctx.lineWidth = 2;
    ctx.beginPath();
    ctx.strokeStyle = majorCol ;
    ctx.lineWidth = majorWidth;

    for(i = gridStart; i <= gridEnd; i+= gridStepMajor)
    {
        ctx.moveTo(gridStart, i);
        ctx.lineTo(gridEnd, i);
        ctx.moveTo(i, gridStart);
        ctx.lineTo(i, gridEnd);
    }
    ctx.stroke();

    ctx.strokeStyle = minorCol;
    ctx.lineWidth = minorWidth;
    for(i = gridStart+gridStepMinor; i < gridEnd; i+= gridStepMinor)
    {
        ctx.moveTo(gridStart, i);
        ctx.lineTo(gridEnd, i);
        ctx.moveTo(i, gridStart);
        ctx.lineTo(i, gridEnd);
    }
    ctx.stroke();

    ctx.fillStyle = "red";
    ctx.strokeStyle = "red";
    ctx.lineWidth = 4;
    ctx.beginPath();
    ctx.arc(50, 50, 6, 0, Math.PI*2);
    ctx.fill();
}

function demo()
{
    canvas = document.createElement("canvas");
    canvas.width = 500;
    canvas.height = 300;
    canvas.ctx = canvas.getContext("2d");

    ctx = canvas.ctx;

    $("#main").append(canvas);

    draw();
}

var timer = 0;
var timerStep = 0.5;
var seconds = 15;

function rotate()
{
    timer += timerStep;

    var cw = canvas.width / 2;
    var ch = canvas.height / 2;

    ctx.setTransform(1, 0, 0, 1, 0, 0);  // reset the transform so we can clear
    ctx.clearRect(0, 0, canvas.width, canvas.height);  // clear the canvas

    createMatrix(cw, ch -50, scale, timer);

    var m = matrix;
    ctx.setTransform(m[0], m[1], m[2], m[3], m[4], m[5]);

    draw();

    if(timer <= rotation )
    {
        requestAnimationFrame(rotate);
    }
}

$(document).ready(function()
{
    demo();

    $(canvas).mousedown(function(e)
    {
        painting = true;
        ctx.fillStyle = "#0000FF";

        mouseWorldPos = toWorld(e.pageX, e.pageY);

        lastX = mouseWorldPos.x;
        lastY = mouseWorldPos.y;
    });

    $(canvas).mousemove(function(e)
    {
        $("#screen").text("X: " + e.pageX + " - Y:" + e.pageY);

        mouseWorldPos = toWorld(e.pageX, e.pageY);
        $("#world").text("X: " + mouseWorldPos.x + " - Y:" + mouseWorldPos.y);

        if (painting)
        {
            mouseX = mouseWorldPos.x;
            mouseY = mouseWorldPos.y;

            // find all points between
            var x1 = mouseX,
                x2 = lastX,
                y1 = mouseY,
                y2 = lastY;


            var steep = (Math.abs(y2 - y1) > Math.abs(x2 - x1));
            if (steep){
                var x = x1;
                x1 = y1;
                y1 = x;

                var y = y2;
                y2 = x2;
                x2 = y;
            }
            if (x1 > x2) {
                var x = x1;
                x1 = x2;
                x2 = x;

                var y = y1;
                y1 = y2;
                y2 = y;
            }

            var dx = x2 - x1,
                dy = Math.abs(y2 - y1),
                error = 0,
                de = dy / dx,
                yStep = -1,
                y = y1;

            if (y1 < y2) {
                yStep = 1;
            }

            lineThickness = 5 - Math.sqrt((x2 - x1) *(x2-x1) + (y2 - y1) * (y2-y1))/10;
            if(lineThickness < 1){
                lineThickness = 1;
            }

            for (var x = x1; x < x2; x++) {
                if (steep) {
                    ctx.fillRect(y, x, lineThickness , lineThickness );
                } else {
                    ctx.fillRect(x, y, lineThickness , lineThickness );
                }

                error += de;
                if (error >= 0.5) {
                    y += yStep;
                    error -= 1.0;
                }
            }

            lastX = mouseX;
            lastY = mouseY;
        }
    });

    $(canvas).mouseup(function(e)
    {
        painting = false;
    });

    $("#btnRotate").click(function()
    {
        rotate();
    });
});

CSS

#main{outline: 1px solid orange; display: inline-block; position: relative;}
span{position: relative;}

样本

https://jsfiddle.net/mgf8uz7s/