javascript - 沿圆弧移动一个点到另一个点的距离
问题描述
我有一个180°的弧。我有两个点(V3 和 V4)被弧长沿弧线绘制。如何将 V4 的位置设置为相对于它与 V3 而不是 V1 的距离?我不想使用角距离,而是 x & y 中的距离。我仍然希望 V4 沿着相同的弧线移动,但我希望能够拖动一个滑块,其正值向 V2 移动,负值向 V1 移动,具体取决于 V3 的位置。
任何帮助都会很棒。谢谢!
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var percentSlider = document.getElementById("percentSlider");
var distanceSlider = document.getElementById("distanceSlider");
var pReadout = document.querySelector(".readout.percent");
var dReadout = document.querySelector(".readout.distance");
var distance = document.getElementById("distance");
class Vector {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
function drawDot(v, txt, color) {
ctx.beginPath();
r = 4;
ctx.arc(v.x, v.y, r, 0, Math.PI * 2, false);
ctx.closePath();
ctx.fillStyle = color;
ctx.fill();
ctx.font = '10px sans-serif';
ctx.fillText(txt, v.x - 6, v.y - 12);
}
function clamp(n, minn, maxn) {
return Math.max(Math.min(maxn, n), minn);
}
function PosByPercent(cx, cy, d, radius, perc) {
angle = perc * Math.PI;
let newX = cx + radius * Math.cos(angle);
let newY = cy - radius * Math.sin(angle);
return new Vector(newX, newY)
}
function PosByDistance(cx, cy, d, radius) {
a = 1 - Math.pow(d / radius, 2) / 2;
a = clamp(a, -1, 1);
angle = Math.acos(a);
let newX = cx + radius * Math.cos(angle);
let newY = cy - radius * Math.sin(angle);
return new Vector(newX, newY)
}
function drawAll() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
let angle = 0;
let d = distanceSlider.value;
let p = percentSlider.value;
let cx = canvas.width / 2;
let cy = canvas.height / 2;
let radius = 70;
v1 = new Vector(cx + radius, cy);
v2 = new Vector(cx - radius, cy);
v3 = PosByPercent(cx, cy, d, radius, p);
v4 = PosByDistance(cx, cy, d, radius, p);
ctx.beginPath();
ctx.arc(cx, cy, radius, Math.PI, 0, false);
ctx.lineWidth = 3;
ctx.strokeStyle = "#3f3f3f";
ctx.stroke();
drawDot(v1, "V1", "#40e4ff");
drawDot(v2, "V2", "#40e4ff");
drawDot(v3, "V3", "#FF0000");
drawDot(v4, "V4", "#00ff48");
}
function getDistances() {
let a = v4.x - v3.x;
let b = v4.y - v3.y;
let c = Math.sqrt(a * a + b * b);
distance.innerHTML = "<div><span>dist - v3 & v4: </span>" + parseFloat(c).toFixed(1) + "</div>";
}
var v1, v2, v3, v4;
drawAll();
getDistances();
dReadout.innerHTML = distanceSlider.value;
pReadout.innerHTML = percentSlider.value;
percentSlider.oninput = function() {
pReadout.innerHTML = percentSlider.value;
drawAll();
getDistances();
}
distanceSlider.oninput = function() {
dReadout.innerHTML = distanceSlider.value;
drawAll();
getDistances();
}
body {
margin: 0px;
font-family: sans-serif;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
#canvas {
background-color: #2b2b2b;
border: 1px solid rgba(0, 0, 0, 0.2);
width: 200px;
height: 200px;
margin-bottom: 4px;
}
#controls {
background-color: white;
position: fixed;
top: 0;
right: 0;
padding: 10px;
width: 200px;
box-sizing: border-box;
}
.row {
display: block;
}
label {
display: block;
text-align: left;
}
label span {
font-size: 10px;
}
.readout {
width: 80px;
font-size: 12px;
text-align: left;
padding-left: 2px;
box-sizing: border-box;
}
#myRange {
width: 130px;
}
#distance {
font-size: 13px;
position: fixed;
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
text-align: left;
top: 0;
left: 0;
background: #333;
color: white;
padding: 10px;
}
#distance span {
color: rgba(255, 255, 255, 0.6);
}
<canvas id="canvas" width=200 height=200></canvas>
<div id="controls">
<div class="row" id="perc">
<label for="percentSlider">V3 <span>(%)</span></label>
<input type="range" step="0.01" min="0" max="1" value="0.75" class="slider" id="percentSlider">
<span class="readout percent"></span>
</div>
<div class="row" id="dist">
<label for="distanceSlider">V4 <span>(dist from V1)</span></label>
<input type="range" step="0.1" min="0" max="360" value="0" class="slider" id="distanceSlider">
<span class="readout distance"></span>
</div>
</div>
<div id="distance"></div>
*** 编辑 *** 我最初是用 Math.PI 的百分比设置 V3(如上面的片段),但通过使用 arc_length/radius 设置两个点的位置来获得所需的结果。
解决方案
当你计算v3
位置时,你知道它angle
是中间结果。
记住这个角度并将其用于计算v4
位置,如下所示:
function PosByDistanceFromV3(cx, cy, d, radius, v3angle) {
a = 1 - Math.pow(d / radius, 2) / 2;
a = clamp(a, -1, 1);
angle = Math.acos(a) + v3angle;
angle = clamp(angle, 0, Math.PI);
let newX = cx + radius * Math.cos(angle);
let newY = cy - radius * Math.sin(angle);
return new Vector(newX, newY)
}
推荐阅读
- flutter - MaterialApp 路由和 BottomNavigationBar
- html - 有没有办法覆盖 Angular Material 表中可扩展行的间距?
- php - Laravel 使用 get() 连接返回的查询
- c# - BenchmarkDotNet 返回值分配内存
- r - 带有外部文件的 R 包示例
- c# - 如何将 Id 从 View 传递给 Create 方法?
- flutter - Flutter 中电台播放器的进度条
- android - 任务“:app:generateDebugBuildConfig”执行失败
- python - Google 图片下载 - 从不下载 - “某些图片无法下载”
- javascript - 如何使用反应路由器 dom Link 将数据从一个页面传递到另一个页面?