gpt4 book ai didi

javascript - HTML5 Canvas : Use context. isPointInPath(x, y) 用于具有更多路径的复杂形状

转载 作者:行者123 更新时间:2023-12-02 15:08:53 24 4
gpt4 key购买 nike

我正在绘制一个复杂的形状,由 6 条细线和两条粗线组成。

在代码中,我打开 8 个路径来执行此操作:

        context.save();
context.lineWidth=2;
var TAB_ABSTAND=10;
var TAB_SAITENZAHL=6;
var TAB_SEITENDICKE=10;
for(var i=0;i<TAB_SAITENZAHL;i++)
{
context.beginPath();
context.moveTo(this.clickedX, this.clickedY+(i*TAB_ABSTAND));
context.lineTo(this.clickedX+this.width, this.clickedY+(i*TAB_ABSTAND));
context.stroke();
}



context.lineWidth=TAB_SEITENDICKE;

context.beginPath();
context.moveTo(this.clickedX, this.clickedY-1);
context.lineTo(this.clickedX, this.clickedY+TAB_ABSTAND*(TAB_SAITENZAHL-1)+1);
context.stroke();

context.beginPath();
context.moveTo(this.clickedX+this.width, this.clickedY-1);
context.lineTo(this.clickedX+this.width, this.clickedY+TAB_ABSTAND*(TAB_SAITENZAHL-1)+1);
context.stroke();

context.restore();

在 Canvas onmousedown 事件中,我想识别是否已单击该形状(或数组中的其他形状之一)来实现拖动。

有没有办法使用 isPointInPath(x,y) 方法来识别“形状”中的其中一条线是否已被单击?

我想要做的是实现一种维护可拖动对象列表的机制。

我发现了什么:

1.) beginPath 是唯一一个以某种方式中断路径的上下文方法,即 isPointInPath 方法无法识别先前的路径

2.) 在具有大笔划的单行上(即 context.lineWidth=10),当 isPointInPath 方法只是没有曲线的单行时,isPointInPath 方法不会返回 true

3.) closePath 将最后一条线的端点绘制到第一条线的起点,但它不会中断路径,因此后面的Stroke() 始终对之前的lineTo 和moveTo 方法生效关闭路径

4.) 如果不调用 beginPath() 而不抚摸其余路径,似乎不可能画出更大的线

5.) moveTo(x,y) 确实跳转到另一个位置,但另一个位置可以是 isPointInPath 方法返回 true 的路径,当它不仅由一行组成时(请参见 1.))。

6.) 为了可视化路径,fill() 方法很有用

那么,当我想识别“线”(绘制为矩形)是否在路径中时,我应该始终使用矩形来绘制线吗?

最佳答案

如何对由多个路径组成的形状进行 HitTest

此形状由 2 条路径组成:路径 1= 4 条红色细线,路径 2= 2 条蓝色粗线。

enter image description here

首先,以下是有关路径的信息,可解释您的观察结果发生的原因

beginPath is the only context method that interrupts the path in a way, that the previous path is not recognized by the isPointInPath method

您可以定义多个路径,但是 isPointInPath只会测试最后定义的路径

路径由一组路径命令组成,如下所示:

  • 路径以 beginPath 开头命令
  • 然后路径用 moveTo 定义其形状, lineTo等命令。
  • 路径以下一个 beginPath 结尾命令。

因此,在您的问题代码中,只会测试最后一个 moveTo+lineTo 。

 context.beginPath();
context.moveTo(this.clickedX+this.width, this.clickedY-1);
context.lineTo(this.clickedX+this.width, this.clickedY+TAB_ABSTAND*(TAB_SAITENZAHL-1)+1);

On a single line with big stroke (i.e. context.lineWidth=10) the isPointInPath method is not returning true when it is just a single line without curves.

从数学上讲,一行不占据空间。因此,您无法测试任何点是否“在”单行中。

在大多数浏览器(尤其是 IE/Edge 除外)中,您可以使用新的 isPointInStroke方法来测试一个点是否在一条直线内。为了跨浏览器兼容性,您必须将单行“加厚”到路径中,以便您可以对该加厚路径内的点进行 HitTest 。

closePath draws the endpoint of the last line to the beginning point of the first line, but it is not interupting the path, so that a later stroke() always takes effect on the lineTo and moveTo-methods before the closePath

恕我直言,closePath名字不好。它不会关闭(不完成)路径。它不是 beginPath 的“左大括号”的“右大括号”。相反,它只是直接从路径中的当前点画一条线回到路径中的第一个点。

It seems to be impossible to draw a bigger line without calling beginPath() without stroking the rest of the pathes

您只能将一种样式应用于一条路径。因此,如果您在一组路径命令中定义多个 lineWidth,则最后一个 lineWidth 获胜,并且整个路径将使用最后一个 linewidth 进行描边。

moveTo(x,y) really jumps to another position, but the other position can be a path that returns true for the isPointInPath method, when it not only consists of one line (see 1.)).

moveTo相当于“拿起笔”并将其移动到纸上的新位置而不结束当前的路径命令集

例如:假设您以 beginPath 开始路径然后使用 moveTo 绘制 3 个独立的三 Angular 形将他们分开。然后所有 3 个三 Angular 形都将包含在路径中,并且所有 3 个三 Angular 形都将使用 isPointInPath 进行测试。 .

To visualize pathes the fill() method is useful

.fill.stroke将命令上下文将当前路径直观地绘制到 Canvas 上。他们没有完成路径——只有下一个beginPath将完成当前路径。因此,如果您定义了三 Angular 形的 2 条边、笔画(),再次定义三 Angular 形的第 3 条边和笔划(),则前 2 条边将被描边两次,第三边将被描边一次。

重要信息:您可以定义路径并使用 isPointInPath 对其进行测试。无需实际抚摸(或填充)测试路径。这意味着您可以单独重新定义 + isPointInPath 你的每条路径都无需在 Canvas 上重新绘制。您还可以定义由多个路径组成的单个形状,并使用 isPointInPath 对该多路径形状进行 HitTest 。

因此,要测试 mousedown 事件中的哪些形状(形状==路径),您可以重新定义每个多路径并使用 context.isPointInPath(mouseX,mouseY) 进行测试。 .

要实际绘制形状,您需要多种样式(细线与粗线),因此您必须单独绘制路径,因为每个路径只能获得 1 个样式。

这里是示例代码和演示:

var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
function reOffset(){
var BB=canvas.getBoundingClientRect();
offsetX=BB.left;
offsetY=BB.top;
}
var offsetX,offsetY;
reOffset();
window.onscroll=function(e){ reOffset(); }
window.onresize=function(e){ reOffset(); }

var isDown=false;
var startX,startY;

var shapes=[];
//
var path1=[
{x:150,y:100},
{x:50,y:100},
{x:25,y:75},
{x:50,y:50},
{x:150,y:50}
];
path1.linewidth=1;
path1.strokestyle='red';
//
var path2=[
{x:150,y:50},
{x:225,y:75},
{x:150,y:100}
];
path2.linewidth=5;
path2.strokestyle='blue';

var shape1=[path1,path2];
shape1.fill='green';
//
shapes.push(shape1);

// draw both parts of the path onto the canvas
draw(path1);
draw(path2);

$("#canvas").mousedown(function(e){handleMouseDown(e);});

function define(shape){
ctx.beginPath();
for(j=0;j<shape.length;j++){
var p=shape[j];
ctx.moveTo(p[0].x,p[0].y);
for(var i=1;i<p.length;i++){
ctx.lineTo(p[i].x,p[i].y);
}
}
}
//
function draw(path){
ctx.beginPath();
ctx.moveTo(path[0].x,path[0].y);
for(var i=1;i<path.length;i++){
ctx.lineTo(path[i].x,path[i].y);
}
ctx.lineWidth=path.linewidth;
ctx.strokeStyle=path.strokestyle;
ctx.stroke();
}
//
function dot(x,y,fill){
ctx.beginPath();
ctx.arc(x,y,2,0,Math.PI*2);
ctx.closePath();
ctx.fillStyle=fill;
ctx.fill();
}

function handleMouseDown(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// get mouseX,mouseY
var mx=parseInt(e.clientX-offsetX);
var my=parseInt(e.clientY-offsetY);
//
var dotcolor='red';
for(var i=0;i<shapes.length;i++){
define(shapes[i]);
if(ctx.isPointInPath(mx,my)){dotcolor=shapes[i].fill;}
}
dot(mx,my,dotcolor);
}
body{ background-color: ivory; }
#canvas{border:1px solid red; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h4>Click inside and outside the multi-path shape<br>Inside clicks become green dots.</h4>
<canvas id="canvas" width=300 height=300></canvas>

关于javascript - HTML5 Canvas : Use context. isPointInPath(x, y) 用于具有更多路径的复杂形状,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34924326/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com