在2条线之间绘制圆弧并绘制2点曲线

时间:2019-03-25 12:01:54

标签: javascript canvas fabricjs

框架:fabricjs

我的第一个问题是在2条线之间绘制一个角度。我的代码可以正常工作,但是我对结果不满意。

我的第二个问题是在2点之间绘制一条曲线。

第一个问题的我的代码。 我有3分: A,B,C

2行: AB,BC

利用这些信息,我计算出距离为10的距离点。

let angle = this.calcAngle(A,B,C);
let distanceAB  = this.calcCornerPoint(A, B, 10);
let distanceBC = this.calcCornerPoint(C, B, 10);

计算角度:

  calcAngle(A, B, C, final, finalAddon = "°") {

    var nx1 = A.x - B.x;
    var ny1 = A.y - B.y;
    var nx2 = C.x - B.x;
    var ny2 = C.y - B.y;

    this.lineAngle1 = Math.atan2(ny1, nx1);
    this.lineAngle2 = Math.atan2(ny2, nx2);

    if (nx1 * ny2 - ny1 * nx2 < 0) { 
      const t = lineAngle2;
      this.lineAngle2 = this.lineAngle1;
      this.lineAngle1 = t;
    }

    // if angle 1 is behind then move ahead
    if (lineAngle1 < lineAngle2) {
      this.lineAngle1 += Math.PI * 2;
    }

  }

比用以下方法绘制路径:

this.drawAngleTrapez(distanceAB, distanceBC, B);

drawAngleTrapez(AB, BC, B) {
    let points = [AB, BC, B];
    let path = "";
    if (this.trapezObjs[this.iterator]) {
      this.canvas.remove(this.trapezObjs[this.iterator]);
    }
    path += "M " + Math.round(points[0].x) + " " + Math.round(points[0].y) + "";
    for (let i = 1; i < points.length; i++) {
      path += " L " + Math.round(points[i].x) + " " + Math.round(points[i].y) + "";
    }

    this.currentTrapez = this.trapezObjs[this.iterator] = new fabric.Path(path, {
      selectable: false,
      hasControls: false,
      hasBorders: false,
      hoverCursor: 'default',
      fill: '#ccc',
      strokeWidth: this.strokeWidth,
    });
    this.canvas.add(this.trapezObjs[this.iterator]);
  }

然后我画一个圆:

drawAnglePoint(B,d = 10) {
    this.currentCorner = new fabric.Circle({
      left: B.x,
      top: B.y,
      startAngle: this.lineAngle1,
      endAngle: this.lineAngle2,
      radius: 10,
      fill: '#ccc',
      selectable: false,
      hasControls: false,
      hasBorders: false,
      hoverCursor: 'default',
    });
    this.canvas.add(this.currentCorner);
  }

但是结果并不理想:

enter image description here

蓝点不在行尾,这里的mabye也有一点修复。

this.startPoint.set({ left: C.x, top: C.y });

第二个问题已解决:是我的计算错误。

问题是,它不是一条漂亮的曲线: enter image description here

1 个答案:

答案 0 :(得分:0)

与其将中心的“楔形”绘制为2个形状(三角形和一部分圆形),而应将其绘制为2边形。

通过提供原点绘制圆形。因此,要在行的末端绘制蓝点,应为端点指定与在圆心处相同的坐标。

以下代码将重新创建您的第一张图片,文字除外。 当我在线条上方透明地绘制后掠角度指示器时,您可能想要更改绘制顺序,颜色和不透明度。

(我使用了0x88 / 0xFF = 136/255 = 53.3%),

"use strict";
function newEl(tag){return document.createElement(tag)}
function byId(id){return document.getElementById(id)}

class vec2
{
	constructor(x,y){this.x = x;this.y = y;}
	get x(){ return this._x; }
	set x(newVal){ this._x = newVal; }
	get y(){ return this._y; }
	set y(newVal){ this._y = newVal; }
	get length(){return Math.hypot(this.x,this.y);}
	set length(len){var invLen = len/this.length; this.timesEquals(invLen);}
	add(other){return new vec2(this.x+other.x, this.y+other.y);}
	sub(other){return new vec2(this.x-other.x, this.y-other.y);}
	plusEquals(other){this.x+=other.x;this.y+=other.y;return this;}
	minusEquals(other){this.x-=other.x;this.y-=other.y;return this;}
	timesEquals(scalar){this.x*=scalar;this.y*=scalar;return this;}
	divByEquals(scalar){this.x/=scalar;this.y/=scalar;return this;}
	setTo(other){this.x=other.x;this.y=other.y;}
	toString(){return `vec2 {x: ${this.x}, y: ${this.y}}` }
	toStringN(n){ return `vec2 {x: ${this.x.toFixed(n)}, y: ${this.y.toFixed(n)}}` }
	dotProd(other){return this.x*other.x + this.y*other.y;}
	timesEquals(scalar){this.x *= scalar;this.y *= scalar;return this;}
	normalize(){let len = this.length;this.x /= len;this.y /= len;return this;}
	static clone(other){let result = new vec2(other.x, other.y);return result;}
	clone(){return vec2.clone(this);}
};

window.addEventListener('load', onWindowLoaded, false);

function onWindowLoaded(evt)
{
	var can = byId('output');
	let A = new vec2(172,602), B = new vec2(734,602), C = new vec2(847,194);
	myTest(can, [A,B,C]);
}

function circle(canvas, x, y, radius)
{
	let ctx = canvas.getContext('2d');
	ctx.moveTo(x,y);
	ctx.beginPath();
	ctx.ellipse(x,y, radius,radius, 0, 0, 2*Math.PI);
	ctx.closePath();
	ctx.fill();
}

function getAngle(origin, pt)
{
	let delta = pt.sub(origin);
	let angle = Math.atan2( delta.y, delta.x );
	return angle;
}

function myTest(canvas, points)
{
	let ctx = canvas.getContext('2d');
	
	// background colour
	//
	ctx.fillStyle = '#ebedf0';
	ctx.fillRect(0,0,canvas.width,canvas.height);

	
	// white square grid
	//
	//60,33 = intersection of first
	//115 = square-size
	ctx.strokeStyle = '#FFFFFF';
	ctx.lineWidth = 12;
	for (let x=60; x<canvas.width; x+=112)
	{
		ctx.beginPath();
		ctx.moveTo(x, 0);
		ctx.lineTo(x, canvas.height);
		ctx.stroke();
		ctx.closePath();
	}
	for (let y=33; y<canvas.height; y+=112)
	{
		ctx.beginPath();
		ctx.moveTo(0, y);
		ctx.lineTo(canvas.width, y);
		ctx.stroke();
		ctx.closePath();
	}
	
	
	// wedge indicating swept angle
	let angle1 = getAngle(points[1], points[2]);
	let angle2 = getAngle(points[1], points[0]);
	ctx.beginPath();
	ctx.moveTo(points[1].x,points[1].y);
	ctx.arc(points[1].x,points[1].y, 70, angle1,angle2, true);
	ctx.fillStyle = '#cccccc88';
	ctx.fill();
	console.log(angle1, angle2);

	// lines
	//
	ctx.lineWidth = 9;
	ctx.strokeStyle = '#c3874c';
	ctx.beginPath();
	ctx.moveTo(points[0].x, points[0].y);
	ctx.lineTo(points[1].x, points[1].y);
	ctx.lineTo(points[2].x, points[2].y);
	ctx.stroke();
	ctx.closePath();

	// points
	//
	ctx.fillStyle = '#3b89c9';
	ctx.beginPath();
	points.forEach( function(pt){circle(canvas, pt.x,pt.y, 10);} );
	ctx.closePath();
}
canvas
{
	zoom: 67%;
}
<canvas id='output' width='996' height='730'></canvas>