Published
Edited
Aug 14, 2020
1 star
Insert cell
Insert cell
Insert cell
Insert cell
{
const { machineCtx, output } = createMachineCtx();

const canvasCtx = DOM.context2d(width, height, window.devicePixelRatio);

// Use machine profile to transform from machine coords to screen
canvasCtx.setTransform(
2 * ((machineProfile.xAxis * width) / machineProfile.width),
0,
0,
2 * ((machineProfile.yAxis * height) / machineProfile.height),
width * 2,
0
);

previewCurve(canvasCtx);

const arcs = curve.arcs(arcTolerance);

machineCtx.beginPath();
canvasCtx.lineWidth = 0.5;
canvasCtx.beginPath();

arcs.forEach(arc => {
const p1 = curve.compute(arc.interval.start);
const p2 = curve.compute(arc.interval.end);

const ccw = arcIsCCW2(arc);

const startAngle = !ccw ? arc.s : arc.e;
const endAngle = !ccw ? arc.e : arc.s;

canvasCtx.arc(arc.x, arc.y, arc.r, startAngle, endAngle, ccw);
machineCtx.arc(arc.x, arc.y, arc.r, startAngle, endAngle, !ccw);
});

machineCtx.stroke();
canvasCtx.stroke();

return html`
<div>
${canvasCtx.canvas}
<hr />
<pre>${output.join('\n')}</pre>
</div>
`;
}
Insert cell
Insert cell
Insert cell
{
const { machineCtx, output } = createMachineCtx();

const canvasCtx = DOM.context2d(width, height, window.devicePixelRatio);

// Use machine profile to transform from machine coords to screen
canvasCtx.setTransform(
2 * ((machineProfile.xAxis * width) / machineProfile.width),
0,
0,
2 * ((machineProfile.yAxis * height) / machineProfile.height),
width * 2,
0
);

previewCurve(canvasCtx);

canvasCtx.beginPath();
machineCtx.beginPath();
for (let i = 0; i <= subdivisions; i++) {
const t = i / subdivisions;
const { x, y } = curve.compute(t);
canvasCtx.lineTo(x, y);
machineCtx.lineTo(x, y);
}
canvasCtx.stroke();
machineCtx.stroke();

return html`
<div>
${canvasCtx.canvas}
<hr />
<pre>${output.join('\n')}</pre>
</div>
`;
}
Insert cell
Insert cell
Insert cell
{
const canvasCtx = DOM.context2d(width, height, window.devicePixelRatio);
// Use machine profile to transform from machine coords to screen
canvasCtx.setTransform(
2 * ((machineProfile.xAxis * width) / machineProfile.width),
0,
0,
2 * ((machineProfile.yAxis * height) / machineProfile.height),
width * 2,
0
);

canvasCtx.lineWidth = 4;
canvasCtx.globalCompositeOperation = 'multiply';

canvasCtx.strokeStyle = 'blue';
canvasCtx.beginPath();
for (let i = 0; i <= subdivisions2; i++) {
const t = i / subdivisions2;
const { x, y } = curve.compute(t);
canvasCtx.lineTo(x, y);
}
canvasCtx.stroke();

const arcs = curve.arcs(arcTolerance2);

canvasCtx.strokeStyle = 'red';
canvasCtx.beginPath();

arcs.forEach(arc => {
const p1 = curve.compute(arc.interval.start);
const p2 = curve.compute(arc.interval.end);

const ccw = arcIsCCW2(arc);

const startAngle = !ccw ? arc.s : arc.e;
const endAngle = !ccw ? arc.e : arc.s;

canvasCtx.arc(arc.x, arc.y, arc.r, startAngle, endAngle, ccw);
});

canvasCtx.stroke();

return canvasCtx.canvas;
}
Insert cell
Insert cell
machineProfile = ({
xAxis: 1,
yAxis: -1,
width: 385,
height: 280
})
Insert cell
height = (machineProfile.height / machineProfile.width) * width // aspect ratio * width
Insert cell
curve = new Bezier(
{ x: -40, y: -40 },
{ x: -200, y: -100 },
{ x: -300, y: -20 },
{ x: -300, y: -200 }
)
Insert cell
function createMachineCtx() {
const output = [];
const driver = new Gcanvas.GcodeDriver({
write: function(cmd) {
output.push(cmd);
}
});

const machineCtx = new Gcanvas(driver);

machineCtx.feed = 1000;

return { machineCtx, output };
}
Insert cell
function createCanvasCtx() {
const canvasCtx = DOM.context2d(width, height, window.devicePixelRatio);

// Use machine profile to transform from machine coords to screen
canvasCtx.setTransform(
2 * ((machineProfile.xAxis * width) / machineProfile.width),
0,
0,
2 * ((machineProfile.yAxis * height) / machineProfile.height),
width * 2,
0
);

return canvasCtx;
}
Insert cell
function arcIsCCW2(arc) {
const start = curve.compute(arc.interval.start);
const center = curve.compute((arc.interval.start + arc.interval.end) / 2);
const end = curve.compute(arc.interval.end);
const c =
(start.x - center.x) * (end.y - center.y) -
(start.y - center.y) * (end.x - center.x);
return c > 0;
}
Insert cell
function arcIsCCW(arc) {
const start = pointOnCircle(arc.x, arc.y, arc.r, arc.s);
const center = { x: arc.x, y: arc.y };
const end = pointOnCircle(arc.x, arc.y, arc.r, arc.e);
const c =
(start.x - center.x) * (end.y - center.y) -
(start.y - center.y) * (end.x - center.x);
return c > 0;
}
Insert cell
function pointOnCircle(x, y, r, angle) {
return {
x: x + Math.cos(angle) * r,
y: y + Math.sin(angle) * r
};
}
Insert cell
function previewCurve(ctx) {
ctx.beginPath();
ctx.strokeStyle = 'red';
ctx.lineWidth = 4;
ctx.globalAlpha = 0.2;
ctx.moveTo(curve.points[0].x, curve.points[0].y);
ctx.bezierCurveTo(
curve.points[1].x,
curve.points[1].y,
curve.points[2].x,
curve.points[2].y,
curve.points[3].x,
curve.points[3].y
);
ctx.stroke();
ctx.strokeStyle = 'black';
ctx.lineWidth = 1;
ctx.globalAlpha = 1;
}
Insert cell
Bezier = require('https://bundle.run/bezier-js@2.6.1')
Insert cell
// Used wzrd.in after a lotta fiddling with other CDNs due to package.json missing `module`
Gcanvas = require('https://wzrd.in/standalone/gcanvas@latest')
Insert cell
import { slider } from '@jashkenas/inputs'
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more