Функция
function bezierCurve(controlPoint1, controlPoint2, line) { }
Предположим, что кривая представляет собой куби c Безье (две контрольные точки). Функция, которую вы задаете, выглядит только как ее найти точку посередине и сместить некоторую фиксированную сумму. вам потребуется больше контроля над тем, где точка находится относительно линии.
Перпендикулярное смещение от линии.
Следующая функция даст вам немного больше контроля, позволяя вам указать, где вдоль линии Вы хотите указать точку и то, как далеко эта точка должна быть от линии.
Аргумент along
и dist
- это дроби линии, такие как along = 0.5
на полпути и dist = 0.2
на 1/5 длина линии прочь. dist > 0
и точка смещена вправо от линии dist < 0
, а смещение находится влево (ось Y направлена вниз)
function pointFromLine(along, dist, p1, p2, res = {}) {
const dx = p2.x - p1.x;
const dy = p2.y - p1.y;
res.x = p1.x + dx * along - dy * dist;
res.y = p1.y + dy * along + dx * dist;
return res;
}
Чтобы найти среднюю точку на 1/5 длины линии от центра
const p1 = {x: 10, y: 10};
const p2 = {x: 510, y: 310};
const offset = pointFromLine(0.5, 0.2, p1, p2);
Чтобы найти две контрольные точки для куби c Безье.
const p1 = {x: 10, y: 10};
const p2 = {x: 510, y: 310};
const cp1 = pointFromLine(0.333, 0.2, p1, p2); // 1/3rd dist from start
const cp2 = pointFromLine(1 - 0.333, 0.2, p1, p2); // equal dist (1/3rd) from end of line
Пример использования
В следующем фрагменте показана используемая функция создать симметричную кривую для куби c Безье. Переместите ползунок для управления dist вдоль линии и смещением dist от линии
function pointFromLine(along, dist, p1, p2, res = {}) {
const dx = p2.x - p1.x;
const dy = p2.y - p1.y;
res.x = p1.x + dx * along - dy * dist;
res.y = p1.y + dy * along + dx * dist;
return res;
}
const p1 = {x: 40, y: 40};
const p2 = {x: 160, y: 160};
const cp1 ={x: 0, y: 0};
const cp2 ={x: 0, y: 0};
const ctx = canvas.getContext("2d");
update();
function drawPoint(p) {
ctx.beginPath();
ctx.arc(p.x, p.y, 4, 0, Math.PI * 2);
ctx.fill();
}
function drawLine(p1, p2) {
ctx.lineWidth = 1;
ctx.beginPath();
ctx.lineTo(p1.x, p1.y);
ctx.lineTo(p2.x, p2.y);
ctx.stroke();
}
function drawCubicBezier(p1, p2, cp1, cp2) {
ctx.lineWidth = 3;
ctx.beginPath();
ctx.lineTo(p1.x, p1.y);
ctx.bezierCurveTo(cp1.x, cp1.y, cp2.x, cp2.y, p2.x, p2.y);
ctx.stroke();
drawLine(p1,cp1);
drawLine(p2,cp2);
drawPoint(p1);
drawPoint(p2);
drawPoint(cp1);
drawPoint(cp2);
}
alongIn.addEventListener("input", update);
distIn.addEventListener("input", update);
function update() {
const a = alongIn.value * 1;
const d = distIn.value * 1;
info.textContent = `Along: ${a.toFixed(2)} Offset: ${d.toFixed(2)}`
ctx.clearRect(0,0,200,200);
drawCubicBezier(
p1,
p2,
pointFromLine(a , d, p1, p2, cp1),
pointFromLine(1 - a, d, p1, p2, cp2)
);
}
canvas {
border: 1px solid black;
}
Dist along: <input id="alongIn" type="range" min="-1" max="2" step="0.01" value="0.3"/>
Dist out: <input id="distIn" type="range" min="-1" max="2" step="0.01" value="0.3"/>
<div id="info"> </div>
<canvas id="canvas" width="200" height="200" ></canvas>