我有一个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");
});
答案 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;}
样本