javascript - 如何在画布中用橡皮筋绘制平行矩形
问题描述
我正在尝试使用画布绘制一组形状。
我在下面引用了 SO 线程:
但无法弄清楚如何在我们拉伸线时计算平行矩形的点。
任何使用画布拉伸形状的参考都值得赞赏。
//Canvas
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
//Variables
var canvasx = $(canvas).offset().left;
var canvasy = $(canvas).offset().top;
var last_mousex = last_mousey = 0;
var mousex = mousey = 0;
var mousedown = false;
// grid parameters
var gridSpacing = 20; // pixels
var gridWidth = 1;
//var gridColor = "#f1f1f1";
var gridColor = "lightgray";
/** */
var originX = 0;
/** */
var originY = 0;
drawGrid();
//Mousedown
$(canvas).on('mousedown', function(e) {
last_mousex = parseInt(e.clientX-canvasx);
last_mousey = parseInt(e.clientY-canvasy);
mousedown = true;
});
//Mouseup
$(canvas).on('mouseup', function(e) {
mousedown = false;
});
//Mousemove
$(canvas).on('mousemove', function(e) {
mousex = parseInt(e.clientX-canvasx);
mousey = parseInt(e.clientY-canvasy);
if(mousedown) {
ctx.clearRect(0,0,canvas.width,canvas.height); //clear canvas
drawGrid();
ctx.setLineDash([5, 15]);
ctx.beginPath();
ctx.moveTo(last_mousex,last_mousey);
ctx.lineTo(mousex,mousey);
//ctx.lineTo(mousex,mousey);
ctx.strokeStyle = 'blue';
ctx.lineDashOffset = 2;
ctx.lineWidth = 5;
ctx.lineJoin = ctx.lineCap = 'round';
ctx.stroke();
startx = last_mousex;
starty = last_mousey;
drawPolygon([last_mousex, mousex, mousex, last_mousex, last_mousex],
[last_mousey-10, mousey-10, mousey-60, last_mousey-60],true, 'gray', false, 'black', 2);
drawPolygon([last_mousex, mousex, mousex, last_mousex, last_mousex],
[last_mousey+10, mousey+10, mousey+60, last_mousey+60],true, 'gray', false, 'black', 2);
}
//Output
$('#output').html('current: '+mousex+', '+mousey+'<br/>last: '+last_mousex+', '+last_mousey+'<br/>mousedown: '+mousedown);
});
/** */
function drawLine(startX, startY, endX, endY, width, color) {
// width is an integer
// color is a hex string, i.e. #ff0000
ctx.beginPath();
ctx.moveTo(startX, startY);
ctx.lineTo(endX, endY);
ctx.lineWidth = width;
ctx.strokeStyle = color;
ctx.stroke();
}
function drawPolygon(xArr, yArr, fill, fillColor, stroke, strokeColor, strokeWidth) {
// fillColor is a hex string, i.e. #ff0000
fill = fill || false;
stroke = stroke || false;
ctx.beginPath();
ctx.moveTo(xArr[0], yArr[0]);
for (var i = 1; i < xArr.length; i++) {
ctx.lineTo(xArr[i], yArr[i]);
}
ctx.closePath();
if (fill) {
ctx.fillStyle = fillColor;
ctx.fill();
}
if (stroke) {
ctx.lineWidth = strokeWidth;
ctx.strokeStyle = strokeColor;
ctx.stroke();
}
//console.log(xArr);
//console.log(yArr);
}
/** returns n where -gridSize/2 < n <= gridSize/2 */
function calculateGridOffset(n) {
if (n >= 0) {
return (n + gridSpacing / 2.0) % gridSpacing - gridSpacing / 2.0;
} else {
return (n - gridSpacing / 2.0) % gridSpacing + gridSpacing / 2.0;
}
}
/** */
function drawGrid() {
var offsetX = calculateGridOffset(-originX);
var offsetY = calculateGridOffset(-originY);
var width = canvas.width;
var height = canvas.height;
for (var x = 0; x <= (width / gridSpacing); x++) {
drawLine(gridSpacing * x + offsetX, 0, gridSpacing * x + offsetX, height, gridWidth, gridColor);
}
for (var y = 0; y <= (height / gridSpacing); y++) {
drawLine(0, gridSpacing * y + offsetY, width, gridSpacing * y + offsetY, gridWidth, gridColor);
}
}
canvas {
cursor: crosshair;
border: 1px solid #000000;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas id="canvas" width="800" height="500"></canvas>
<div id="output"></div>
解决方案
我猜这就是你想要的。
与其尝试手动绘制旋转线,不如将画布的原点移动到线的开头,
// save the canvas state
ctx.save();
// move origin to start of line
ctx.translate(last_mousex, last_mousey);
然后旋转原点,使其指向正 X 方向的直线末端
// compute direction of line from start to end
const dx = mousex - last_mousex;
const dy = mousey - last_mousey;
const angle = Math.atan2(dy, dx);
// rotate to point to end of line
ctx.rotate(angle);
然后计算从开始到结束的线的长度
// compute length of line
const length = Math.sqrt(dx * dx + dy * dy);
并在该长度的正 x 方向上画一个箭头
ctx.setLineDash([5, 15]);
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(length, 0);
ctx.strokeStyle = 'blue';
ctx.lineDashOffset = 2;
ctx.lineWidth = 5;
ctx.lineJoin = ctx.lineCap = 'round';
ctx.stroke();
drawPolygon([0, length, length, 0, 0],
[-10, -10, -60, -60],true, 'gray', false, 'black', 2);
drawPolygon([0, length, length, 0, 0],
[+10, +10, +60, +60],true, 'gray', false, 'black', 2);
// restore the canvas state
ctx.restore();
当我们在这里时,如果页面滚动,您用于计算鼠标位置的代码不起作用。这将获得鼠标相对于画布中像素的位置。
const rect = canvas.getBoundingClientRect();
mousex = (e.clientX - rect.left) * canvas.width / canvas.clientWidth;
mousey = (e.clientY - rect.top ) * canvas.height / canvas.clientHeight;
//Canvas
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
//Variables
var last_mousex = last_mousey = 0;
var mousex = mousey = 0;
var mousedown = false;
// grid parameters
var gridSpacing = 20; // pixels
var gridWidth = 1;
//var gridColor = "#f1f1f1";
var gridColor = "lightgray";
/** */
var originX = 0;
/** */
var originY = 0;
drawGrid();
//Mousedown
$(canvas).on('mousedown', function(e) {
const rect = canvas.getBoundingClientRect();
last_mousex = (e.clientX - rect.left) * canvas.width / canvas.clientWidth;
last_mousey = (e.clientY - rect.top ) * canvas.height / canvas.clientHeight;
mousedown = true;
});
//Mouseup
$(canvas).on('mouseup', function(e) {
mousedown = false;
});
//Mousemove
$(canvas).on('mousemove', function(e) {
const rect = canvas.getBoundingClientRect();
mousex = (e.clientX - rect.left) * canvas.width / canvas.clientWidth;
mousey = (e.clientY - rect.top ) * canvas.height / canvas.clientHeight;
if(mousedown) {
ctx.clearRect(0,0,canvas.width,canvas.height); //clear canvas
drawGrid();
// save the canvas state
ctx.save();
// move origin to start of line
ctx.translate(last_mousex, last_mousey);
// compute direction of line from start to end
const dx = mousex - last_mousex;
const dy = mousey - last_mousey;
const angle = Math.atan2(dy, dx);
// rotate to point to end of line
ctx.rotate(angle);
// compute length of line
const length = Math.sqrt(dx * dx + dy * dy);
ctx.setLineDash([5, 15]);
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(length, 0);
ctx.strokeStyle = 'blue';
ctx.lineDashOffset = 2;
ctx.lineWidth = 5;
ctx.lineJoin = ctx.lineCap = 'round';
ctx.stroke();
drawPolygon([0, length, length, 0, 0],
[-10, -10, -60, -60],true, 'gray', false, 'black', 2);
drawPolygon([0, length, length, 0, 0],
[+10, +10, +60, +60],true, 'gray', false, 'black', 2);
// restore the canvas state
ctx.restore();
}
//Output
$('#output').html('current: '+mousex+', '+mousey+'<br/>last: '+last_mousex+', '+last_mousey+'<br/>mousedown: '+mousedown);
});
/** */
function drawLine(startX, startY, endX, endY, width, color) {
// width is an integer
// color is a hex string, i.e. #ff0000
ctx.beginPath();
ctx.moveTo(startX, startY);
ctx.lineTo(endX, endY);
ctx.lineWidth = width;
ctx.strokeStyle = color;
ctx.stroke();
}
function drawPolygon(xArr, yArr, fill, fillColor, stroke, strokeColor, strokeWidth) {
// fillColor is a hex string, i.e. #ff0000
fill = fill || false;
stroke = stroke || false;
ctx.beginPath();
ctx.moveTo(xArr[0], yArr[0]);
for (var i = 1; i < xArr.length; i++) {
ctx.lineTo(xArr[i], yArr[i]);
}
ctx.closePath();
if (fill) {
ctx.fillStyle = fillColor;
ctx.fill();
}
if (stroke) {
ctx.lineWidth = strokeWidth;
ctx.strokeStyle = strokeColor;
ctx.stroke();
}
//console.log(xArr);
//console.log(yArr);
}
/** returns n where -gridSize/2 < n <= gridSize/2 */
function calculateGridOffset(n) {
if (n >= 0) {
return (n + gridSpacing / 2.0) % gridSpacing - gridSpacing / 2.0;
} else {
return (n - gridSpacing / 2.0) % gridSpacing + gridSpacing / 2.0;
}
}
/** */
function drawGrid() {
var offsetX = calculateGridOffset(-originX);
var offsetY = calculateGridOffset(-originY);
var width = canvas.width;
var height = canvas.height;
for (var x = 0; x <= (width / gridSpacing); x++) {
drawLine(gridSpacing * x + offsetX, 0, gridSpacing * x + offsetX, height, gridWidth, gridColor);
}
for (var y = 0; y <= (height / gridSpacing); y++) {
drawLine(0, gridSpacing * y + offsetY, width, gridSpacing * y + offsetY, gridWidth, gridColor);
}
}
canvas {
cursor: crosshair;
border: 1px solid #000000;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas id="canvas" width="800" height="500"></canvas>
<div id="output"></div>
推荐阅读
- pip - PyPI 为什么我需要 pip --upgrade 两次?
- flutter - build 方法多久调用一次?
- python - 如何限制范围内的用户输入?
- python - 如何在 tensorboard 中显示 Tensorflow 2.0 中的 tf.data.Dataset.map 子图?
- python - 调整 LSTM 自动编码器性能
- android - 是否需要 setContentView() 来为片段充气?
- javascript - 我应该将哪个 FileystemDirectory 用于临时文件?
- javascript - 更改 ReactJs 中的对象状态值给我一个警告(不要直接改变状态。使用 setState()
- javascript - 使用express在Node.js中成功后如何发送JSON响应并重定向到某个html页面?
- r - 使用 plotly 创建填充区域线图