#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>