live plot example and screenToPlot helper
This commit is contained in:
@@ -320,6 +320,38 @@ class WallPlotter {
|
||||
this.timingMultiplier = Math.max(0.1, Number(mult) || 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert canvas pixel coordinates to plot coordinates in mm.
|
||||
* By default this uses machine bounds so live-click targeting stays stable.
|
||||
* @param {number} px
|
||||
* @param {number} py
|
||||
* @param {{clamp?: boolean, useDisplayBounds?: boolean}} [options]
|
||||
*/
|
||||
screenToPlot(px, py, options = {}) {
|
||||
const layout = this._getPlotLayout();
|
||||
const bounds =
|
||||
options.useDisplayBounds === true
|
||||
? this._getDisplayBounds()
|
||||
: {
|
||||
xMin: this.machineXMin,
|
||||
xMax: this.machineXMax,
|
||||
yMin: this.machineYMin,
|
||||
yMax: this.machineYMax,
|
||||
};
|
||||
|
||||
const scale = Math.max(layout.scale || 0, 1e-9);
|
||||
const worldX = (px - layout.cx) / scale + layout.worldCx;
|
||||
const worldY = -(py - layout.cy) / scale + layout.worldCy;
|
||||
const clamp = options.clamp !== false;
|
||||
|
||||
if (!clamp) return { x: worldX, y: worldY };
|
||||
|
||||
return {
|
||||
x: Math.min(bounds.xMax, Math.max(bounds.xMin, worldX)),
|
||||
y: Math.min(bounds.yMax, Math.max(bounds.yMin, worldY)),
|
||||
};
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// Public API — path buffer (queue only; nothing is sent until runPath)
|
||||
// ===========================================================================
|
||||
@@ -929,19 +961,42 @@ class WallPlotter {
|
||||
/** Pen up and travel to (x, y) mm immediately. Requires home. */
|
||||
async moveTo(x, y) {
|
||||
if (!this._requireHome()) return;
|
||||
const startX = this.x;
|
||||
const startY = this.y;
|
||||
await this.penUp();
|
||||
await this.send(`G1 X${this._fmt(x)} Y${this._fmt(y)} F${this.feedRateTravel}`);
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
await this._waitForMotionComplete(
|
||||
Math.hypot((x ?? 0) - (startX ?? 0), (y ?? 0) - (startY ?? 0)),
|
||||
this.feedRateTravel
|
||||
);
|
||||
}
|
||||
|
||||
/** Pen down and draw to (x, y) mm immediately. Requires home. */
|
||||
async drawTo(x, y) {
|
||||
if (!this._requireHome()) return;
|
||||
const startX = this.x;
|
||||
const startY = this.y;
|
||||
await this.penDown();
|
||||
await this.send(`G1 X${this._fmt(x)} Y${this._fmt(y)} F${this.feedRateDraw}`);
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
await this._waitForMotionComplete(
|
||||
Math.hypot((x ?? 0) - (startX ?? 0), (y ?? 0) - (startY ?? 0)),
|
||||
this.feedRateDraw
|
||||
);
|
||||
}
|
||||
|
||||
async _waitForMotionComplete(distanceMm, feedRateMmPerMin) {
|
||||
const distance = Number.isFinite(distanceMm) ? Math.max(0, distanceMm) : 0;
|
||||
const speedMmPerS = Math.max(1, Number(feedRateMmPerMin) || 1) / 60;
|
||||
const etaMs = Math.round((distance / speedMmPerS) * 1000);
|
||||
await this.send('M400', {
|
||||
timeoutMs: Math.max(WallPlotter.OK_TIMEOUT_MS, etaMs + 15000),
|
||||
// M400 legitimately blocks until mechanics are done moving.
|
||||
waitLogAfterMs: Math.max(WallPlotter.OK_WAIT_LOG_MS, etaMs + 1500),
|
||||
});
|
||||
}
|
||||
|
||||
/** Travel to (0, 0). */
|
||||
|
||||
Reference in New Issue
Block a user