Мое решение - это тоже не настоящий эллипсис, как подчеркивает @ Mike'Pomax'Kamermans, а эллипсисоподобная кривая Безье.Если half означает точку деления 3: 1 для длины нижней кривой (а не 45 градусов от оси), решение выглядит так с помощью ctx и использованием @ ivan-kuckir's функция интерполяции :
function interpolate(a, b, frac){
var nx = a.x+(b.x-a.x)*frac;
var ny = a.y+(b.y-a.y)*frac;
return {x:nx, y:ny};
}
function getDivisionPointOfBezier(cp1, cp2, cp3, cp4, frac) {
var p1 = interpolate(cp1, cp2, frac);
var p2 = interpolate(cp2, cp3, frac);
var p3 = interpolate(cp3, cp4, frac);
var p4 = interpolate(p1, p2, frac);
var p5 = interpolate(p2, p3, frac);
var p6 = interpolate(p4, p5, frac);
return p6;
}
// control points of the ellipsis bezier
var cp1 = {x:0, y:50};
var cp2 = {x:0, y:100};
var cp3 = {x:200, y:100};
var cp4 = {x:200, y:50};
var cp5 = {x:200, y:0};
var cp6 = {x:0, y:0};
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
// bottom half-curve
ctx.moveTo(cp1.x, cp1.y);
ctx.bezierCurveTo(cp2.x, cp2.y, cp3.x, cp3.y, cp4.x, cp4.y);
// top half-curve
ctx.moveTo(cp4.x, cp4.y);
ctx.bezierCurveTo(cp5.x, cp5.y, cp6.x, cp6.y, cp1.x, cp1.y);
ctx.stroke();
// draw red point
var divPoint = getDivisionPointOfBezier(cp1, cp2, cp3, cp4, 0.75);
ctx.beginPath();
ctx.fillStyle = 'red';
ctx.arc(divPoint.x,divPoint.y,5,0,2*Math.PI);
ctx.fill();
<canvas id="myCanvas" width="200" height="100" style="border:1px solid #d3d3d3;">
</canvas>
На этом чертеже представлен расчет в нижней части.Вот как алгоритм Безье вычисляет положение каждой точки (черные точки представляют контрольные точки), и мы ищем точку деления 3: 1.