<html>
<body style="margin:10px;">
<canvas id="myCanvas" width="500" height="500" style="border:1px solid #d3d3d3;">
</canvas>
</body>
<script language="javascript" type="text/javascript">
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var centerX = 400;
var centerY = 400;
var radius = .5;
context.beginPath(400,400);
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
context.fillStyle = 'blue';
context.fill();
context.lineWidth = 1;
context.strokeStyle = '#003300';
context.stroke();
context.beginPath();
context.moveTo(50, 250);
context.bezierCurveTo(50, 250, 50, 250, 50, 250);
context.bezierCurveTo(90, 210, 90, 210, 90, 210);
context.bezierCurveTo(130, 90, 130, 90, 130, 90);
context.bezierCurveTo(260, 240, 260, 240, 260, 240);
context.bezierCurveTo(255, 400, 255, 400, 255, 400);
context.closePath();
context.lineWidth = 1;
context.strokeStyle = 'green';
context.stroke();
</script>
</html>
第一次在这里发帖,但是这个网站对我已经拥有的其他灰色区域有很大的帮助!
我想确定从画布上的一个点到形状边缘的距离。形状将是不规则的,因此,例如,如果它是一个三角形,我不认为距离公式如果落在三角形的边缘之外就会起作用。
我有点沮丧,因为这可能是我项目的垮台。任何开放的想法将不胜感激!
谢谢
编辑:这是我正在谈论的一个例子,在这个例子中,我想知道从400-400,400到对象的最近点有多少像素。但对于我的项目,无论这个点在哪里,我都希望能够测量到对象的最近点。
我知道这有很多要问,但我想我会试一试!
感谢您提前回复!
答案 0 :(得分:2)
这个问题的范围很大,我可以写一个解决方案。我将概述如何添加一些限制。
形状是一组弧,线,曲线(立方和二次)和可以连接或不连接的矩形。距离将是定义每个形状的线上的最近点,并且不包括线宽。形状都是相同的比例和方向。
最好的方法是使用MarkE指出的距离线功能(在他的评论“find the least distance from the point”中)并将所有路径对象转换为线。细分每条曲线的精确程度将决定位置的准确程度,直线不需要细分。但假设你只是在一个像素(鼠标分辨率)之后,那么代码处理的时间并不会太多。
您可以将线条定义为点集。由于您可能有未连接的路径,因此这些点集将位于二维数组中。
var lines = [];
var currentLine = null;
function startLine(){
if(currentLine.length > 0){
currentLine = []; // new array
lines.push(cuurentLine); // push onto the line array
}
}
function moveToPoint(x,y){
startLine();
addPoint(x,y);
}
function addPoint(x,y){
currentLine.push(x:x,y:y);
}
function closePath(){
currentLine.push(currentLine[0]);
}
然后,您可以匹配所有渲染调用以及对上述函数的调用
最简单的一组线
ctx.beginPath();
ctx.moveTo(x,y); // to save me time x and y are points of some coordinate.
ctx.lineTo(x,y);
ctx.lineTo(x,y);
ctx.lineTo(x,y);
ctx.closePath();
应与
匹配startLine(); // you really only need moveToPoint
moveToPoint(x,y);
addPoint(x,y);
addPoint(x,y);
addPoint(x,y);
closePath();
您的数组应该看起来像
// p represents a point {x :x,y: y}
lines [[p,p,p,p,p]]; // An array inside lines with 5 points. The last point is
// back to the start
如果您添加其他路径
ctx.moveTo(x,y); // to save me time x and y are points of some coordinate.
ctx.lineTo(x,y);
ctx.lineTo(x,y);
ctx.lineTo(x,y);
// note I did not close path
您必须将其与
匹配moveToPoint(x,y);
addPoint(x,y);
addPoint(x,y);
addPoint(x,y);
数组现在看起来像
// p represents a point {x :x,y: y}
lines [[p,p,p,p,p],[p,p,p,p]]; // not second path is not closed and has one less point
并包含两个路径。
然后您可以使用线功能(在答案顶部链接)检查以找到最接近形状的点
function findclosestPoint(px,py){ // the point px,py
var minDist = Infinity;
var pf = {x:0,y:0}; // the closest point
for(i = 0; i < lines.length; i+=1){
for(j = 0; j < lines[i].length-1; j+=1){
var p = lines[i][j];
var p1 = lines[i][j+1];
// get closet point
var cp = getClosestPointOnLine({x0 : p.x, y0 : p.y, x1 : p1.x, y1 : p1.y},px,py);
// then get the distance.
var x = cp.x - px;
var y = cp.y - py;
x *= x;
y *= y;
var dist = Math.sqrt(x + y);
// is it the closest?
if(dist < minDist){
minDist = dist; // yes remember this distance
pf.x = cp.x;
pf.y = cp.y;
}
}
}
return {dist : minDist, point : pf};
}
对于您只需要调用该函数的形状,您就可以获得解决方案。
var closest = findclosestPoint(400,400);
console.log(closest.point) ;// >> {x:?,y:?}
console.log(closest.dist) ;// >> ? in pixels
要使其适用于弧,请创建一个将弧分成较小线段的函数。贝塞尔曲线和三次曲线相同。相距约2至3个像素的间隔点应该足够多。有很多例子可以在StackOverflow中找到弧和贝塞尔曲线上的点。
以矩形为例
ctx.rect(x,y,w,h);
创建一个函数来添加定义矩形的线条。
function addRect(x,y,w,h)
addPoint(x,y) // rects start at top left
addPoint(x+w,y)
addPoint(x+w,y+h)
addPoint(x,y+h)
addPoint(x,y)
}
请记住,fillrect和strokeRect以moveTo开头,因此如果需要,可以添加moveToPoint函数调用。
对弧和贝塞尔曲线执行相同的操作。
这就是它的全部内容。
如果您计划使用不同的比例和旋转,则在向线阵列添加点时必须添加这些转换。
如果要包含线宽,则必须为线条的每个边创建线条。对于beziers来说这可能很棘手,但是stackoverflow中的每个子问题都有解决方案。从基础知识开始,并进一步完善,直到达到目标。