V-Plotter
HTML
<h3>Click and drag on the canvas to update position of the print head</h3>
<p>
<label for="d">Distance between mounting points (mm)</label><br />
<input
id="d"
type="range"
min="100"
max="10000"
value="2000"
oninput="update()"
/>
</p>
<canvas id="canvas" width="1000" height="1000">V-Plotter graphic</canvas>
CSS
body {
margin: 40px;
font-family: Arial, Helvetica, sans-serif;
font-size: 14px;
line-height: 20px;
}
canvas {
border: 1px solid;
}
JavaScript
// printhead mass (kg)
let m = 1;
const ctx = canvas.getContext("2d");
ctx.font = "14px sans-serif";
ctx.textAlign = "center";
let alpha, beta, Fg, Fa, Fb, scaleForce, a, b, scale;
let dragging = false;
// printhead coordinates (mm)
let x = 450, y = 200;
// offset for drawing everything (px)
const offset = 50;
update();
function update() {
// plotter width (mm)
let width = d.value;
// convert to pixel dimensions
scale = (canvas.width - 2 * offset) / width;
// gravity pull on printhead (N)
Fg = m * 9.81;
// scale all force vectors so that Fg always is 100 px
scaleForce = 100 / Fg;
// length of ropes (mm)
a = Math.round(Math.sqrt(x ** 2 + y ** 2) / scale);
b = Math.round(
Math.sqrt((canvas.width - 2 * offset - x) ** 2 + y ** 2) / scale,
);
// how much rope a deviates from vertical (radians)
alpha = Math.atan(x / y);
// how much rope b deviates from vertical (radians)
beta = Math.atan((width * scale - x) / y);
// the angle between both ropes (radians)
let theta = alpha + beta;
// https://technikdoku.com/zentrales-kraeftesystem/#Zerlegen_einer_Kraft_in_zwei_nicht_parallele_Kraefte
// force pulling on rope b (N)
Fb = (Fg * Math.sin(alpha)) / Math.sin(Math.PI - theta);
// force pulling on rope a (N)
Fa = Fg * Math.cos(alpha) - Fb * Math.cos(theta);
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawPlotter(scale * width, x, y, a, b);
}
// expects dimensions in px
function drawPlotter(w, x, y, a, b) {
// ropes
ctx.beginPath();
ctx.moveTo(offset, offset);
ctx.lineTo(x + offset, y + offset);
ctx.lineTo(w + offset, offset);
ctx.strokeStyle = "black";
ctx.lineWidth = 2;
ctx.stroke();
// mounting points and carriage
ctx.beginPath();
ctx.moveTo(offset, offset);
ctx.arc(offset, offset, 5, 0, 2 * Math.PI);
ctx.moveTo(w + offset, offset);
ctx.arc(w + offset, offset, 5, 0, 2 * Math.PI);
ctx.moveTo(x + offset, y +...