/* Jog.tsx - ESP3D WebUI component file Copyright (c) 2021 Luc LEBOSSE. All rights reserved. This code is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with This code; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ import { Fragment } from "preact" import { Move, Home, ChevronDown, Edit3, StopCircle, MoreHorizontal, } from "preact-feather" import { useTargetCommands } from "../../hooks" import { useUiContextFn, useModalsContext } from "../../contexts" import { T } from "../Translations" import { Button, ButtonImg, FullScreenButton, CloseButton, ContainerHelper } from "../Controls" import { useEffect, useState } from "preact/hooks" import { showModal } from "../Modal" import { useTargetContext } from "../../targets" let currentFeedRate: Record = {} let currentJogDistanceXY: any = "-1" let currentJogDistanceZ: any = "-1" let currentAxis: string = "-1" const feedList = ["XY", "Z", "A", "B", "C", "U", "V", "W"] const selectableAxisLettersList = ["A", "B", "C", "U", "V", "W"] /* * Local const * */ //A separate control to avoid the full panel to be updated when the positions are updated interface PositionsControlsProps { onWPosClick: (letter: string, position: string) => void } const PositionsControls = ({ onWPosClick }: PositionsControlsProps) => { const { positions } = useTargetContext() const posLines = [ ["x", "y", "z"], ["a", "b", "c"], ["u", "v", "w"], ] return ( {posLines.map((line) => { if ( typeof positions[line[0]] != "undefined" || typeof positions[`w${line[0]}`] != "undefined" ) return (
{line.map((letter) => { if ( (typeof positions[letter] != "undefined" || typeof positions[`w${letter}`] != "undefined") && useUiContextFn.getValue(`show${letter}`) ) { return (
{typeof positions[letter] != "undefined" && (
MPos{" "} {letter.toUpperCase()}
{positions[letter]}
)} {typeof positions[`w${letter}`] != "undefined" && (
WPos{" "} {letter.toUpperCase()}
{ useUiContextFn.haptic() onWPosClick(letter, positions[ `w${letter}` ]) }} > { positions[ `w${letter}` ] }
)}
) } })}
) })}
) } const JogPanel = () => { const { modals } = useModalsContext() const [currentSelectedAxis, setCurrentSelectedAxis] = useState(currentAxis) const { positions } = useTargetContext() const id = "jogPanel" const onChangeAxis = (e: any) => { let value = e.target ? e.target.value : e setCurrentSelectedAxis(value) currentAxis = value } const { targetCommands } = useTargetCommands() //Send Home command const sendHomeCommand = (axis: string) => { let selected_axis if (axis == "Axis") selected_axis = currentAxis else selected_axis = axis const cmd = useUiContextFn .getValue("homecmd") .replace("#", selected_axis) targetCommands(cmd) } //Send Zero command const sendZeroCommand = (axis: string) => { let selected_axis: string if (axis == "Axis") selected_axis = `${currentAxis }0` else selected_axis = `${axis }0` if (axis.length == 0) { selected_axis = "" "xyzabcuvw".split("").reduce((acc, letter) => { if (positions[letter] || positions[`w${letter}`]) acc += selected_axis += ` ${letter.toUpperCase() }0` return acc }, "") } const cmd = useUiContextFn .getValue("zerocmd") .replace("#", selected_axis.trim()) targetCommands(cmd) } const sendMoveToCommand = (axis: string, targetPosition: string) => { let upperAxis = axis.toUpperCase() let selected_axis: string let feedrate = upperAxis.startsWith("X") || upperAxis.startsWith("Y") ? currentFeedRate["XY"] : upperAxis.startsWith("Z") ? currentFeedRate["Z"] : currentFeedRate[currentAxis] if (axis.startsWith("Axis")) selected_axis = axis.replace("Axis", currentAxis) else selected_axis = axis let cmd = `$J=G90 G21 ${selected_axis.toUpperCase()}${targetPosition} F${feedrate}` targetCommands(cmd) } const showMoveToDialog = (axis: string, currentPosition: string) => { let targetValue = currentPosition const axisUpper = axis.toUpperCase() showModal({ modals, title: `Move to ${axisUpper} position`, button2: { text: T("S28") }, button1: { cb: () => { if (targetValue.length > 0 && !isNaN(parseFloat(targetValue))) { sendMoveToCommand(axisUpper, targetValue) } }, text: T("S43"), id: "applyMoveToBtn", }, icon: , id: "inputMoveTo", content: (
{T("CN15")?.replace("$", axisUpper) || `Enter target ${axisUpper} position:`}
{ targetValue = (e.target as HTMLInputElement).value.trim() const btn = document.getElementById("applyMoveToBtn") as HTMLButtonElement if (btn) { btn.disabled = targetValue.length === 0 || isNaN(targetValue as any) } }} />
), }) } const sendJogCommand = (axis: string) => { let selected_axis: string let distance: string | number let feedrate = axis.startsWith("X") || axis.startsWith("Y") ? currentFeedRate["XY"] : axis.startsWith("Z") ? currentFeedRate["Z"] : currentFeedRate[currentAxis] // Determine which distance to use based on axis if (axis.startsWith("X") || axis.startsWith("Y")) { distance = currentJogDistanceXY } else if (axis.startsWith("Z")) { distance = currentJogDistanceZ } else { distance = currentJogDistanceXY // Default for other axes } if (axis.startsWith("Axis")) selected_axis = axis.replace("Axis", currentAxis) else selected_axis = axis let cmd = `$J=G91 G21 ${selected_axis }${distance } F${feedrate}` targetCommands(cmd) } //click distance button const onCheckXY = (e: any, distance: number | string) => { e.target.blur() currentJogDistanceXY = distance } //click distance button for Z const onCheckZ = (e: any, distance: number | string) => { e.target.blur() currentJogDistanceZ = distance } //Set the current feedrate for axis const setFeedrate = (axis: string) => { let value = currentFeedRate[axis] let t if (axis == "XY") { t = T("CN2") } else { t = T("CN3").replace("$", axis) } showModal({ modals, title: t, button2: { text: T("S28") }, button1: { cb: () => { if (value.length > 0.1 as any) currentFeedRate[axis] = value }, text: T("S43"), id: "applyFrBtn", }, icon: , id: "inputFeedrate", content: (
{t}
{ value = (e.target as HTMLInputElement).value.trim() const btn = document.getElementById("applyFrBtn") as HTMLButtonElement if (parseFloat(value) < 0.1) { if (btn) { btn.disabled = true } } else { if (btn) { btn.disabled = false } } }} />
), }) } // Axis selector for additional axes (A, B, C, U, V, W) const selectorBtn = (type: string) => { if (type == "prev" || type == "next") { const axisList = selectableAxisLettersList.reduce( (acc: string[], letter) => { if ( (positions[letter.toLowerCase()] || positions[`w${letter.toLowerCase()}`]) && useUiContextFn.getValue( `show${[letter.toLowerCase()]}` ) ) { acc.push(letter) } return acc }, [] ) if (axisList.length > 1) { let index = axisList.indexOf(currentAxis) if (type == "next") { index++ if (index >= axisList.length) index = 0 } else { index-- if (index < 0) index = axisList.length - 1 } const selectElement = document.getElementById("selectAxisList") as HTMLSelectElement if (selectElement) { selectElement.value = axisList[index] onChangeAxis(axisList[index]) } } } } useEffect(() => { if(currentJogDistanceXY == "-1") { currentJogDistanceXY = useUiContextFn.getValue("jogdistancedefault") } if(currentJogDistanceZ == "-1") { currentJogDistanceZ = useUiContextFn.getValue("zjogdistancedefault") || "10" } if (currentAxis == "-1") { feedList.forEach((letter) => { if (!currentFeedRate[letter]) { currentFeedRate[letter] = useUiContextFn.getValue( `${letter.toLowerCase() }feedrate` ) } feedList.forEach((letter) => { if (!(letter == "XY" || letter == "Z")) { if ( currentAxis == "-1" && useUiContextFn.getValue( `show${letter.toLowerCase()}` ) && (positions[letter.toLowerCase()] || positions[`w${letter.toLowerCase()}`]) ) { currentAxis = letter } } }) }) setCurrentSelectedAxis(currentAxis) } }) return (
{/* XY Group */}
{/* X and Y axes with shared distance selector */} {["X", "Y"].map((letter) => { if ( (positions[letter.toLowerCase()] || positions[`w${letter.toLowerCase()}`]) && useUiContextFn.getValue( `show${letter.toLowerCase()}` ) ) { return (
{useUiContextFn.getValue( "homesingleaxis" ) && ( )}
) } })} {/* XY Distance Selector */}
mm
{ useUiContextFn.haptic() onCheckXY(e, 100) }} />
{ useUiContextFn.haptic() onCheckXY(e, 50) }} />
{ useUiContextFn.haptic() onCheckXY(e, 10) }} />
{ useUiContextFn.haptic() onCheckXY(e, 1) }} />
{ useUiContextFn.haptic() onCheckXY(e, 0.1) }} />
{/* Z axis with its own distance selector */} {(positions.z || positions.wz) && useUiContextFn.getValue("showz") && (
{useUiContextFn.getValue("homesingleaxis") && ( )}
{/* Z Distance Selector */}
mm
{ useUiContextFn.haptic() onCheckZ(e, 50) }} />
{ useUiContextFn.haptic() onCheckZ(e, 25) }} />
{ useUiContextFn.haptic() onCheckZ(e, 10) }} />
{ useUiContextFn.haptic() onCheckZ(e, 1) }} />
{ useUiContextFn.haptic() onCheckZ(e, 0.1) }} />
)}
{selectableAxisLettersList.reduce((acc, letter) => { if ( useUiContextFn.getValue( `show${letter.toLowerCase()}` ) && (positions[letter.toLowerCase()] || positions[`w${letter.toLowerCase()}`]) ) acc = true return acc }, false as boolean) && (
{ selectorBtn("next") }} />
{ selectorBtn("prev") }} />
{useUiContextFn.getValue("homesingleaxis") && ( )}
)} {(positions.x || positions.wx || positions.y || positions.wy || positions.z || positions.wz || positions.a || positions.wa || positions.b || positions.wb || positions.c || positions.wc) && (
} data-tooltip={T("CN23")} onClick={(e: any) => { useUiContextFn.haptic(); (e.target as HTMLElement).blur(); const cmds = useUiContextFn .getValue("jogstopcmd") targetCommands(cmds, ";") }} />
)}
) } const JogPanelElement = { id: "jogPanel", content: , name: "S66", icon: "Move", show: "showjogpanel", onstart: "openjogonstart", settingid: "jog", } export { JogPanel, JogPanelElement, PositionsControls }