нарисуйте дугу между 2 линиями и нарисуйте кривую в 2 точки

#javascript #canvas #fabricjs

#javascript #холст #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);
  }
  

Но результат не является красивым:

введите описание изображения здесь

И синяя точка находится не на конце линии, может быть, здесь тоже немного исправлено.

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

Вторая проблема решена: была ошибка в моих расчетах.

Проблема в том, что это некрасивая кривая: введите описание изображения здесь

Комментарии:

1. Что именно вы подразумеваете под «результат не красивый» в первом выпуске? Не могли бы вы, пожалуйста, лучше описать свои ожидания в этом случае?

2. пробел между двумя объектами

Ответ №1:

Вместо того, чтобы рисовать центральный «клин» в виде двух фигур — треугольника и части круга, вы должны вместо этого нарисовать его в виде двусторонней фигуры, которой он и является.

Круги рисуются путем указания начала координат. Следовательно, чтобы нарисовать синюю точку в конце линии, вы должны указать те же координаты для конечной точки, что и для центра окружности.

Приведенный ниже код воссоздаст ваше первое изображение, за исключением текста. Хотя я нарисовал индикатор угла наклона прозрачно, поверх линий, вы, вероятно, захотите изменить порядок рисования, цвет и непрозрачность.

(Я использовал 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 resu<}
	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>