javascript - 如何开始允许在网格上的点之间绘制矢量?
问题描述
在基本上只使用 Python 和 C# 之后,我目前正在努力过渡到 HTML5 和 Java。
我正在(尝试)制作一个点网格,请参见下面的代码,在点击时在点之间画线(参见下面的代码),最终结果是我可以使用它绘制平面图(我是一名建筑商)。
我还试图弄清楚如何单独删除绘制的线条,而不必按下“重置”按钮,也许可以通过右键单击它们。
无论如何,由于太新了,这让我非常头疼。我一直在摆弄 paper.js 和 jquery,而且这几天真的没有运气。
你们中的任何人都可以为我指明正确的方向,以获取我所追求的教程/示例或关于在哪里寻求帮助的任何建议吗?
如果做不到这一点,如何使该网格上的“点”“可点击”并使其与向量的起点和终点相对应?
我已经包含了我在下面工作的代码。
点阵:
https://codepen.io/veljamatic/pen/pypxRR
向量,使用 paper.js(由页面底部的教程最终结果http://paperjs.org/tutorials/geometry/vector-geometry/制成):
var values = {
fixLength: false,
fixAngle: false,
showCircle: false,
showAngleLength: true,
showCoordinates: false
};
var vectorStart, vector, vectorPrevious;
var vectorItem, items, dashedItems;
function processVector(event, drag) {
vector = event.point - vectorStart;
if (vectorPrevious) {
if (values.fixLength && values.fixAngle) {
vector = vectorPrevious;
} else if (values.fixLength) {
vector.length = vectorPrevious.length;
} else if (values.fixAngle) {
vector = vector.project(vectorPrevious);
}
}
drawVector(drag);
}
function drawVector(drag) {
if (items) {
for (var i = 0, l = items.length; i < l; i++) {
items[i].remove();
}
}
if (vectorItem)
vectorItem.remove();
items = [];
var arrowVector = vector.normalize(10);
var end = vectorStart + vector;
vectorItem = new Group([
new Path([vectorStart, end]),
new Path([
end + arrowVector.rotate(135),
end,
end + arrowVector.rotate(-135)
])
]);
vectorItem.strokeWidth = 0.75;
vectorItem.strokeColor = '#e4141b';
// Display:
dashedItems = [];
// Draw Circle
if (values.showCircle) {
dashedItems.push(new Path.Circle({
center: vectorStart,
radius: vector.length
}));
}
// Draw Labels
if (values.showAngleLength) {
drawAngle(vectorStart, vector, !drag);
if (!drag)
drawLength(vectorStart, end, vector.angle < 0 ? -1 : 1, true);
}
var quadrant = vector.quadrant;
if (values.showCoordinates && !drag) {
drawLength(vectorStart, vectorStart + [vector.x, 0],
[1, 3].indexOf(quadrant) != -1 ? -1 : 1, true, vector.x, 'x: ');
drawLength(vectorStart, vectorStart + [0, vector.y],
[1, 3].indexOf(quadrant) != -1 ? 1 : -1, true, vector.y, 'y: ');
}
for (var i = 0, l = dashedItems.length; i < l; i++) {
var item = dashedItems[i];
item.strokeColor = 'black';
item.dashArray = [1, 2];
items.push(item);
}
// Update palette
values.x = vector.x;
values.y = vector.y;
values.length = vector.length;
values.angle = vector.angle;
}
function drawAngle(center, vector, label) {
var radius = 25, threshold = 10;
if (vector.length < radius + threshold || Math.abs(vector.angle) < 15)
return;
var from = new Point(radius, 0);
var through = from.rotate(vector.angle / 2);
var to = from.rotate(vector.angle);
var end = center + to;
dashedItems.push(new Path.Line(center,
center + new Point(radius + threshold, 0)));
dashedItems.push(new Path.Arc(center + from, center + through, end));
var arrowVector = to.normalize(7.5).rotate(vector.angle < 0 ? -90 : 90);
dashedItems.push(new Path([
end + arrowVector.rotate(135),
end,
end + arrowVector.rotate(-135)
]));
if (label) {
// Angle Label
var text = new PointText(center
+ through.normalize(radius + 10) + new Point(0, 3));
text.content = Math.floor(vector.angle * 100) / 100 + '°';
text.fillColor = 'black';
items.push(text);
}
}
function drawLength(from, to, sign, label, value, prefix) {
var lengthSize = 5;
if ((to - from).length < lengthSize * 4)
return;
var vector = to - from;
var awayVector = vector.normalize(lengthSize).rotate(90 * sign);
var upVector = vector.normalize(lengthSize).rotate(45 * sign);
var downVector = upVector.rotate(-90 * sign);
var lengthVector = vector.normalize(
vector.length / 2 - lengthSize * Math.sqrt(2));
var line = new Path();
line.add(from + awayVector);
line.lineBy(upVector);
line.lineBy(lengthVector);
line.lineBy(upVector);
var middle = line.lastSegment.point;
line.lineBy(downVector);
line.lineBy(lengthVector);
line.lineBy(downVector);
dashedItems.push(line);
if (label) {
// Length Label
var textAngle = Math.abs(vector.angle) > 90
? textAngle = 180 + vector.angle : vector.angle;
// Label needs to move away by different amounts based on the
// vector's quadrant:
var away = (sign >= 0 ? [1, 4] : [2, 3]).indexOf(vector.quadrant) != -1
? 8 : 0;
value = value || vector.length;
var text = new PointText({
point: middle + awayVector.normalize(away + lengthSize),
content: (prefix || '') + Math.floor(value * 1000) / 1000,
fillColor: 'black',
justification: 'center'
});
text.rotate(textAngle);
items.push(text);
}
}
var dashItem;
function onMouseDown(event) {
var end = vectorStart + vector;
var create = false;
if (event.modifiers.shift && vectorItem) {
vectorStart = end;
create = true;
} else if (vector && (event.modifiers.option
|| end && end.getDistance(event.point) < 10)) {
create = false;
} else {
vectorStart = event.point;
}
if (create) {
dashItem = vectorItem;
vectorItem = null;
}
processVector(event, true);
// document.redraw();
}
function onMouseDrag(event) {
if (!event.modifiers.shift && values.fixLength && values.fixAngle)
vectorStart = event.point;
processVector(event, event.modifiers.shift);
}
function onMouseUp(event) {
processVector(event, false);
if (dashItem) {
dashItem.dashArray = [1, 2];
dashItem = null;
}
vectorPrevious = vector;
}
解决方案
请阅读我的代码中的注释。
为此,您可以添加一个按钮菜单: 为了绘制最后一条线,您需要删除点数组中的最后一个点 为了开始一组新的线,您可以创建一个点数组数组。
我希望这将帮助您开始您的项目。
const ctx = canvas.getContext("2d");
let cw = (canvas.width = window.innerWidth);
let ch = (canvas.height = window.innerWidth);
//the size of the cell relative to the width of the window
let size = cw / 50;
// the cells array
let cells = [];
// the points array.
let points = [];
class Cell {
constructor(x, y, r) {
this.x = x;
this.y = y;
this.r = r;
}
draw() {
ctx.beginPath();
ctx.moveTo(this.x - this.r, this.y - this.r);
ctx.lineTo(this.x + this.r, this.y - this.r);
ctx.lineTo(this.x + this.r, this.y + this.r);
ctx.lineTo(this.x - this.r, this.y + this.r);
ctx.closePath();
//no stroke
}
center() {
// this is drawing a dot in the middle of the cell
ctx.beginPath();
ctx.arc(this.x, this.y, 2, 0, 2 * Math.PI);
ctx.fill();
}
}
// draw the grid of cells
for (let y = size / 2; y < ch; y += 2 * size) {
for (let x = size / 2; x < cw; x += 2 * size) {
cells.push(new Cell(x, y, size));
}
}
cells.forEach(c => {
//uncomment to see the cells
//c.draw()
//ctx.stroke();
c.center();
});
canvas.addEventListener("click", evt => {
// the mouse position
let m = oMousePos(canvas, evt);
// clear the context
ctx.clearRect(0, 0, cw, ch);
//redraw every center
cells.forEach(c => {
c.center();
});
for (let i = 0; i < cells.length; i++) {
cells[i].draw();
//check if the mouse is inside the cell
if (ctx.isPointInPath(m.x, m.y)) {
// marc the clicked cel with a red dot
ctx.fillStyle = "red";
cells[i].center();
//store the number of the clicked cell in the points array
points.push(i);
ctx.fillStyle = "black";
//exit the loop
break;
}
}
if(points.length >0){drawLines();}
});
function drawLines() {
ctx.beginPath();
ctx.strokeStyle = "black";
ctx.moveTo(cells[points[0]].x, cells[points[0]].y);
for (let i = 1; i < points.length; i++) {
ctx.lineTo(cells[points[i]].x, cells[points[i]].y);
}
ctx.stroke();
}
// a function to detect the mouse position
function oMousePos(canvas, evt) {
var ClientRect = canvas.getBoundingClientRect();
return {
x: Math.round(evt.clientX - ClientRect.left),
y: Math.round(evt.clientY - ClientRect.top)
};
}
function Init() {
// get again the size of the canvas
cw = canvas.width = window.innerWidth;
ch = canvas.height = window.innerWidth;
//the size of every cell
size = cw / 50;
// empty the cells array
cells = [];
// draw again the grid of cells
for (let y = size / 2; y < ch; y += 2 * size) {
for (let x = size / 2; x < cw; x += 2 * size) {
cells.push(new Cell(x, y, size));
}
}
//draw the center of every cell
cells.forEach(c => {
c.center();
});
//draw the lines
if(points.length >0){drawLines();}
}
window.setTimeout(function() {
Init();
window.addEventListener("resize", Init, false);
}, 15);
canvas{background:#efefef}
<canvas id="canvas"></canvas>
推荐阅读
- node.js - 如何检查一个文档是否链接到 MongoDB 中的另一个文档
- r - R plot gam 3D表面也显示实际响应值
- reactjs - 如何管理我的子组件状态数组?
- java - 滑动到新片段并在 tabLayout 中滑动回上一个片段时应用程序崩溃
- sql - 我如何给出按时间段分组的条件?
- c# - 使用 sharepoint 2010 async 的 wcf 下载(获取流)文件
- shell - UNIX 无法归档文件
- .htaccess - 使用 htaccess 从 blog.domain.org 重定向到 domain.com
- java - 如何使用弹簧状态机在状态转换期间抛出异常
- regex - 删除不只包含字符的行