我有一个x,y坐标数组,当绘制到画布时会创建一个形状但是当我缩放图像时,我有一个“连接点”版本,因为每个点之间都有空格。
我尝试在每组坐标之间绘制一条线,但由于它没有跟随“轮廓”,因此产生了锯齿形图。
我怎样才能创建大纲?
编辑: 我需要获取形状的“向量”并将其传递给Web应用程序中的线条绘制功能。我没有直接访问画布。
var canvas = document.getElementById("myCanvas");
var canvasWidth = canvas.width;
var canvasHeight = canvas.height;
var ctx = canvas.getContext("2d");
var canvasData = ctx.getImageData(0, 0, canvasWidth, canvasHeight);
// That's how you define the value of a pixel //
function drawPixel (x, y, r=0, g=0, b=0, a=255) {
var index = (x + y * canvasWidth) * 4;
canvasData.data[index + 0] = r;
canvasData.data[index + 1] = g;
canvasData.data[index + 2] = b;
canvasData.data[index + 3] = a;
}
// That's how you update the canvas, so that your //
// modification are taken in consideration //
function updateCanvas() {
ctx.putImageData(canvasData, 0, 0);
}
var i;
var coords = [74,16,76,16,78,16,80,16,82,16,84,16,86,16,88,16,90,16,92,16,70,18,72,18,74,18,76,18,78,18,80,18,82,18,84,18,86,18,88,18,90,18,92,18,94,18,68,20,70,20,72,20,74,20,76,20,78,20,80,20,82,20,84,20,86,20,88,20,90,20,92,20,94,20,96,20,98,20,66,22,68,22,70,22,72,22,74,22,76,22,88,22,90,22,92,22,94,22,96,22,98,22,64,24,66,24,68,24,70,24,72,24,74,24,92,24,94,24,96,24,98,24,100,24,64,26,66,26,68,26,70,26,72,26,94,26,96,26,98,26,100,26,64,28,66,28,68,28,70,28,94,28,96,28,98,28,100,28,102,28,62,30,64,30,66,30,68,30,96,30,98,30,100,30,102,30,62,32,64,32,66,32,68,32,96,32,98,32,100,32,102,32,62,34,64,34,66,34,68,34,96,34,98,34,100,34,102,34,62,36,64,36,66,36,68,36,96,36,98,36,100,36,102,36,62,38,64,38,66,38,68,38,98,38,100,38,102,38,62,40,64,40,66,40,68,40,96,40,98,40,100,40,102,40,62,42,64,42,66,42,68,42,96,42,98,42,100,42,102,42,62,44,64,44,66,44,68,44,96,44,98,44,100,44,102,44,64,46,66,46,68,46,70,46,94,46,96,46,98,46,100,46,102,46,64,48,66,48,68,48,70,48,72,48,94,48,96,48,98,48,100,48,64,50,66,50,68,50,70,50,72,50,74,50,92,50,94,50,96,50,98,50,100,50,66,52,68,52,70,52,72,52,74,52,76,52,88,52,90,52,92,52,94,52,96,52,98,52,68,54,70,54,72,54,74,54,76,54,78,54,80,54,82,54,84,54,86,54,88,54,90,54,92,54,94,54,96,54,98,54,70,56,72,56,74,56,76,56,78,56,80,56,82,56,84,56,86,56,88,56,90,56,92,56,94,56,74,58,76,58,78,58,80,58,82,58,84,58,86,58,88,58,90,58,92,58];
for (i=0; i<coords.length; i+=2) {
drawPixel(coords[i],coords[i+1]);
}
updateCanvas();
<!DOCTYPE html>
<html>
<body>
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;"></canvas>
</body>
</html>
答案 0 :(得分:2)
你很幸运,你的积分很顺序。但如果你有其他一些不是那样的点,那么你会遇到一些问题。
有些功能可以处理更多的随机点,但它们非常复杂,而且我没有找到任何可用的在线点。
对于你给出的点,我使用了一种在一组点周围找到凸包的方法。 (称为格雷厄姆的扫描)。我给你的分数,它返回外面的路径。我必须通过在x和y中进行排序来修改它以处理共线点,这样它才能处理高达10000像素的点云。
复杂的位是中心的洞。
为此,我创建了一组点,在您的形状上创建了一个点矩形(称为蒙版)。然后我移除了在坐标中的掩码中的所有点。我删除了在最后一步计算出的船体外的所有点。
现在面具只是船体内的点,而不是原始坐标的一部分。然后我围绕它创建一个船体并改变它的方向。
我现在有两个路径,一个用于外部,一个用于内部,如果一起渲染,则根据需要绘制形状。
警告。这仅适用于与您所呈现的相似的坐标。仅适用于凸形。你可以调整它,但它是一种蛮力方法,在目前的限制条件下不能很好地工作。
哦,当我添加演示时,我注意到内圈已经出局了。没有办法解决它而不是删除我会留下这个答案。它可能有所帮助。
看完之后我会删除它。
// create and add a canvas
var canvas = document.createElement("canvas");
canvas.width = canvas.height = 256;
var ctx = canvas.getContext("2d");
document.body.appendChild(canvas);
// clear it
ctx.setTransform(1,0,0,1,0,0)
ctx.clearRect(0,0,canvas.width,canvas.height)
//==============================================================================
// Many functions requiered for the example
//==============================================================================
// returns a convex hull around a set of points
// using Graham Scan. See wiki for details
// points in the form [[x,y],[x,y],...]
// returns the convex hull as a list of referances to points
function boundingHull(points) {
var pLen, p, s, hull, i, p1, j, len;
var isRight = (a, b, c) => 0 <= (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]);
points.sort((a, b) => (a[0] + a[1] / 10000) - (b[0] + b[1] / 10000) );
pLen = points.length - 1;
p = points;
s = [];
hull = [];
s.push(p[0],p[1]);
for(j = 0; j < 2; j ++){
for (i = 2; i <= pLen; i++) {
p1 = j === 0 ? p[i] : p[pLen - i];
len = s.length;
while (len > 1 && !isRight(s[len - 2], s[len - 1], p1)) {
s.pop();
len = s.length;
}
s.push(p1);
}
hull.push(...s);
s.length = 0;
s.push(p[pLen],p[pLen-1]);
}
return hull;
}
// gets the center of a set of point
function findCenter(verts){
var x = 0;
var y = 0;
verts.forEach(v => { x += v[0]; y += v[1]; })
x /= verts.length;
y /= verts.length;
return {x,y};
}
// gets the extent of points
function findExtent(verts){
var minx = Infinity;
var maxx = -Infinity;
var miny = Infinity;
var maxy = -Infinity;
var y = 0;
verts.forEach(v => {
minx = v[0] < minx ? v[0] : minx;
miny = v[1] < miny ? v[1] : miny;
maxx = v[0] > maxx ? v[0] : maxx;
maxy = v[1] > maxy ? v[1] : maxy;
});
return {
top : miny,
left : minx,
width : maxx- minx,
height : maxy - miny,
}
}
// moves points
function translate(verts,by){
verts.forEach(v => { v[0] += by.x; v[1] += by.y; })
}
// converts flat array of points into an array of points
// [x,y,x,y,x,y,... ] into [[x,y],[x,y],[x,y],... ]
function formatVerts(verts) {
var v = [];
for (var i = 0; i < verts.length; i += 2) {
v.push([verts[i], verts[i + 1]]);
}
return v;
}
// returns true if point x,y is inside hull
function isInsideHull(x,y,hull){
var s,ss;
var vx,vy;
var px,py;
for(var i = 1; i < hull.length; i ++){
vx = hull[i][0] - hull[i-1][0]
vy = hull[i][1] - hull[i-1][1]
px = x - hull[i-1][0]
py = y - hull[i-1][1]
s = Math.sign(vx * py - vy * px);
s = s === 0 ? 1 : s;
if(ss === undefined){
ss = s;
}else if(ss !== s){
return false;
}
}
return true;
}
// returns only points inside the hull
function removePointsOutsideHull(points,hull){
return points.filter(p => isInsideHull(p[0],p[1],hull))
}
// returns only points that are not in hull
function removePointsFromPoints(hull,points){
return points.filter(p => !hull.some(h => h[0] === p[0] && h[1] === p[1]));
}
// creates a set of points covering extent and spaced by xS,yS
function createOrderedPoints(extent,xS,yS){
var a = [];
for(var y = extent.top; y <= extent.top + extent.height; y += yS ){
for(var x = extent.left; x <= extent.left + extent.width; x += xS ){
a.push([x,y]);
}
}
return a;
}
// display scale
var scale = 5;
ctx.setTransform(scale,0,0,scale,canvas.width /2 ,canvas.height / 2)
//==============================================================================
// drawing functions
//==============================================================================
// draws an array of points
function drawPoints(points, col = "black",size = 3){
var s = ((size - 1) / 2) / scale;
size = size / scale;
ctx.strokeStyle = col;
points.forEach(p => ctx.strokeRect(p[0]-s,p[1]-s,size,size))
}
// sets out a path from an array of points
function definePath(path){
path.forEach((p,i) =>{
if(i === 0){
ctx.moveTo(p[0],p[1]);
}else{
ctx.lineTo(p[0],p[1]);
}
});
}
// draws a path using stroke
function drawPath(path, col = "black", lineWidth = 1){
ctx.strokeStyle = col;
ctx.lineWidth = lineWidth/scale;
ctx.lineJoin = "round"
ctx.beginPath();
definePath(path)
ctx.stroke();
}
// draws a set of paths as a shape
function fillShape(paths, col = "black"){
ctx.fillStyle = col;
ctx.beginPath();
paths.forEach(definePath);
ctx.fill();
}
// define the points
var coords = [74, 16, 76, 16, 78, 16, 80, 16, 82, 16, 84, 16, 86, 16, 88, 16, 90, 16, 92, 16, 70, 18, 72, 18, 74, 18, 76, 18, 78, 18, 80, 18, 82, 18, 84, 18, 86, 18, 88, 18, 90, 18, 92, 18, 94, 18, 68, 20, 70, 20, 72, 20, 74, 20, 76, 20, 78, 20, 80, 20, 82, 20, 84, 20, 86, 20, 88, 20, 90, 20, 92, 20, 94, 20, 96, 20, 98, 20, 66, 22, 68, 22, 70, 22, 72, 22, 74, 22, 76, 22, 88, 22, 90, 22, 92, 22, 94, 22, 96, 22, 98, 22, 64, 24, 66, 24, 68, 24, 70, 24, 72, 24, 74, 24, 92, 24, 94, 24, 96, 24, 98, 24, 100, 24, 64, 26, 66, 26, 68, 26, 70, 26, 72, 26, 94, 26, 96, 26, 98, 26, 100, 26, 64, 28, 66, 28, 68, 28, 70, 28, 94, 28, 96, 28, 98, 28, 100, 28, 102, 28, 62, 30, 64, 30, 66, 30, 68, 30, 96, 30, 98, 30, 100, 30, 102, 30, 62, 32, 64, 32, 66, 32, 68, 32, 96, 32, 98, 32, 100, 32, 102, 32, 62, 34, 64, 34, 66, 34, 68, 34, 96, 34, 98, 34, 100, 34, 102, 34, 62, 36, 64, 36, 66, 36, 68, 36, 96, 36, 98, 36, 100, 36, 102, 36, 62, 38, 64, 38, 66, 38, 68, 38, 98, 38, 100, 38, 102, 38, 62, 40, 64, 40, 66, 40, 68, 40, 96, 40, 98, 40, 100, 40, 102, 40, 62, 42, 64, 42, 66, 42, 68, 42, 96, 42, 98, 42, 100, 42, 102, 42, 62, 44, 64, 44, 66, 44, 68, 44, 96, 44, 98, 44, 100, 44, 102, 44, 64, 46, 66, 46, 68, 46, 70, 46, 94, 46, 96, 46, 98, 46, 100, 46, 102, 46, 64, 48, 66, 48, 68, 48, 70, 48, 72, 48, 94, 48, 96, 48, 98, 48, 100, 48, 64, 50, 66, 50, 68, 50, 70, 50, 72, 50, 74, 50, 92, 50, 94, 50, 96, 50, 98, 50, 100, 50, 66, 52, 68, 52, 70, 52, 72, 52, 74, 52, 76, 52, 88, 52, 90, 52, 92, 52, 94, 52, 96, 52, 98, 52, 68, 54, 70, 54, 72, 54, 74, 54, 76, 54, 78, 54, 80, 54, 82, 54, 84, 54, 86, 54, 88, 54, 90, 54, 92, 54, 94, 54, 96, 54, 98, 54, 70, 56, 72, 56, 74, 56, 76, 56, 78, 56, 80, 56, 82, 56, 84, 56, 86, 56, 88, 56, 90, 56, 92, 56, 94, 56, 74, 58, 76, 58, 78, 58, 80, 58, 82, 58, 84, 58, 86, 58, 88, 58, 90, 58, 92, 58];
// convert to correct format
coords = formatVerts(coords);
// find the center
var center = findCenter(coords);
// find the extent
var extent = findExtent(coords);
// create masking points from extent
var mask = createOrderedPoints(extent,2,2);
// remove points that are the in the coords list
mask = removePointsFromPoints(coords,mask);
// center the mask
translate(mask,{x : - center.x, y : -center.y})
// center the coords
translate(coords,{x : - center.x, y : -center.y})
// create a convex hull
var hull = boundingHull(coords);
// draw the hull
drawPath(hull);
// and the poitns
drawPoints(coords);
// remove all points from the mask outside the hull
mask = removePointsOutsideHull(mask,hull);
// draw remaining points in the mask
//drawPoints(mask,"red");
// create a hull around the mask
var hullInside = boundingHull(mask);
// reverse its direction
hullInside = hullInside.reverse();
// draw the mask points
drawPath(hullInside,"red");
// draw the shape
fillShape([hull,hullInside],"rgba(0,255,0,0.5)");
答案 1 :(得分:1)
在a brief search on MDN之后,正如我所看到的,您有两个可能或可能不会有效的常规选项:
正确,弯曲的方式 - 使用路径并以某种方式计算基于点的呃需要的曲率(这可能很困难),
简单的“放大像素”方式 - 不是绘制像素,而是绘制1像素的矩形,并在缩放图像时缩放它们。