501 lines
16 KiB
JavaScript
501 lines
16 KiB
JavaScript
import { useContext, useState, useEffect } from 'react'
|
|
import {
|
|
Typography,
|
|
Spin,
|
|
Flex,
|
|
Space,
|
|
Collapse,
|
|
InputNumber,
|
|
Descriptions,
|
|
Button,
|
|
Divider
|
|
} from 'antd'
|
|
import { LoadingOutlined, CaretRightOutlined } from '@ant-design/icons'
|
|
import { ApiServerContext } from '../context/ApiServerContext'
|
|
import styled from 'styled-components'
|
|
import PropTypes from 'prop-types'
|
|
import BoolDisplay from './BoolDisplay'
|
|
import merge from 'lodash/merge'
|
|
import { round } from '../utils/Utils'
|
|
const { Text } = Typography
|
|
|
|
const CustomCollapse = styled(Collapse)`
|
|
.ant-collapse-header {
|
|
padding: 0 !important;
|
|
}
|
|
.ant-collapse-content-box {
|
|
padding-left: 0 !important;
|
|
padding-right: 0 !important;
|
|
padding-bottom: 0 !important;
|
|
}
|
|
`
|
|
|
|
const PrinterPositionPanel = ({
|
|
id,
|
|
showControls = true,
|
|
showMoreInfo = true
|
|
}) => {
|
|
const { subscribeToObjectEvent, connected, sendObjectAction } =
|
|
useContext(ApiServerContext)
|
|
const [positionData, setPositionData] = useState({
|
|
speedFactor: 1.0, // eslint-disable-line
|
|
speed: 100,
|
|
extrudeFactor: 1.0, // eslint-disable-line
|
|
absoluteCoordinates: true, // eslint-disable-line
|
|
absoluteExtrude: false, // eslint-disable-line
|
|
homingOrigin: [0.0, 0.0, 0.0, 0.0], // eslint-disable-line
|
|
toolheadPosition: [0.0, 0.0, 0.0, 0.0],
|
|
gcodePosition: [0.0, 0.0, 0.0, 0.0], // eslint-disable-line
|
|
livePosition: [0.0, 0.0, 0.0, 0.0],
|
|
maxVelocity: 1000,
|
|
maxAcceleration: 1000,
|
|
squareCornerVelocity: 100,
|
|
minCruiseRatio: 0
|
|
})
|
|
|
|
useEffect(() => {
|
|
if (id && connected == true) {
|
|
const motionEventUnsubscribe = subscribeToObjectEvent(
|
|
id,
|
|
'printer',
|
|
'motion',
|
|
(event) => {
|
|
setPositionData((prev) => {
|
|
const merged = merge({}, prev, event.data)
|
|
return merged
|
|
})
|
|
}
|
|
)
|
|
return () => {
|
|
if (motionEventUnsubscribe) motionEventUnsubscribe()
|
|
}
|
|
}
|
|
}, [id, connected])
|
|
const [speedFactor, setSpeedFactor] = useState(positionData.speedFactor)
|
|
const [extrudeFactor, setExtrudeFactor] = useState(positionData.extrudeFactor)
|
|
const [maxVelocity, setMaxVelocity] = useState(positionData.maxVelocity)
|
|
const [maxAcceleration, setMaxAcceleration] = useState(
|
|
positionData.maxAcceleration
|
|
)
|
|
const [squareCornerVelocity, setSquareCornerVelocity] = useState(
|
|
positionData.squareCornerVelocity
|
|
)
|
|
const [minCruiseRatio, setMinCruiseRatio] = useState(
|
|
positionData.minCruiseRatio
|
|
)
|
|
|
|
useEffect(() => {
|
|
if (positionData.speedFactor !== undefined) {
|
|
setSpeedFactor(positionData.speedFactor)
|
|
}
|
|
if (positionData.extrudeFactor !== undefined) {
|
|
setExtrudeFactor(positionData.extrudeFactor)
|
|
}
|
|
if (positionData.maxVelocity !== undefined) {
|
|
setMaxVelocity(positionData.maxVelocity)
|
|
}
|
|
if (positionData.maxAcceleration !== undefined) {
|
|
setMaxAcceleration(positionData.maxAcceleration)
|
|
}
|
|
if (positionData.squareCornerVelocity !== undefined) {
|
|
setSquareCornerVelocity(positionData.squareCornerVelocity)
|
|
}
|
|
if (positionData.minCruiseRatio !== undefined) {
|
|
setMinCruiseRatio(positionData.minCruiseRatio)
|
|
}
|
|
}, [
|
|
positionData.speedFactor,
|
|
positionData.extrudeFactor,
|
|
positionData.maxVelocity,
|
|
positionData.maxAcceleration,
|
|
positionData.squareCornerVelocity,
|
|
positionData.minCruiseRatio
|
|
])
|
|
|
|
const handleSetSpeedFactor = () => {
|
|
if (id && connected == true) {
|
|
sendObjectAction(id, 'printer', {
|
|
type: 'setSpeedFactor',
|
|
data: {
|
|
speedFactor: speedFactor * 100
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
const handleSetExtrudeFactor = () => {
|
|
if (id && connected == true) {
|
|
sendObjectAction(id, 'printer', {
|
|
type: 'setExtrudeFactor',
|
|
data: {
|
|
extrudeFactor: extrudeFactor * 100
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
const handleSetMaxVelocity = () => {
|
|
if (id && connected == true) {
|
|
sendObjectAction(id, 'printer', {
|
|
type: 'setMaxVelocity',
|
|
data: {
|
|
maxVelocity: maxVelocity
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
const handleSetMaxAcceleration = () => {
|
|
if (id && connected == true) {
|
|
sendObjectAction(id, 'printer', {
|
|
type: 'setMaxAcceleration',
|
|
data: {
|
|
maxAcceleration: maxAcceleration
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
const handleSetSquareCornerVelocity = () => {
|
|
if (id && connected == true) {
|
|
sendObjectAction(id, 'printer', {
|
|
type: 'setSquareCornerVelocity',
|
|
data: {
|
|
squareCornerVelocity: squareCornerVelocity
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
const handleSetMinCruiseRatio = () => {
|
|
if (id && connected == true) {
|
|
sendObjectAction(id, 'printer', {
|
|
type: 'setMinCruiseRatio',
|
|
data: {
|
|
minCruiseRatio: minCruiseRatio
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
const moreInfoItems = [
|
|
{
|
|
key: '1',
|
|
label: 'More Position Data',
|
|
children: (
|
|
<>
|
|
<Divider style={{ margin: '0 0 12px 0' }} />
|
|
<Flex vertical gap={'middle'}>
|
|
<Text>GCode Position:</Text>
|
|
<Descriptions
|
|
column={1}
|
|
size='small'
|
|
bordered
|
|
styles={{ label: { width: '40px' } }}
|
|
>
|
|
<Descriptions.Item label='X'>
|
|
{' '}
|
|
{round(positionData.gcodePosition[0], 2)}mm
|
|
</Descriptions.Item>
|
|
|
|
<Descriptions.Item label='Y'>
|
|
{round(positionData.gcodePosition[1], 2)}mm
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label='Z'>
|
|
{round(positionData.gcodePosition[2], 2)}mm
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label='E'>
|
|
{round(positionData.gcodePosition[3], 2)}mm
|
|
</Descriptions.Item>
|
|
</Descriptions>
|
|
{showControls && (
|
|
<>
|
|
<Space direction='vertical' style={{ width: '100%' }}>
|
|
<Space direction='horizontal'>
|
|
<Text>Max Velocity:</Text>
|
|
<Space.Compact block size='small'>
|
|
<InputNumber
|
|
value={round(maxVelocity, 2)}
|
|
min={1}
|
|
max={10000}
|
|
step={5}
|
|
style={{ width: '125px' }}
|
|
suffix='mm/s'
|
|
onChange={(value) => setMaxVelocity(value)}
|
|
onPressEnter={handleSetMaxVelocity}
|
|
size='small'
|
|
/>
|
|
<Button
|
|
type='default'
|
|
style={{ width: 40 }}
|
|
onClick={handleSetMaxVelocity}
|
|
>
|
|
Set
|
|
</Button>
|
|
</Space.Compact>
|
|
</Space>
|
|
|
|
<Space direction='vertical' style={{ width: '100%' }}>
|
|
<Space direction='horizontal'>
|
|
<Text>Max Acceleration:</Text>
|
|
<Space.Compact block size='small'>
|
|
<InputNumber
|
|
value={round(maxAcceleration, 2)}
|
|
min={1}
|
|
max={10000}
|
|
step={5}
|
|
style={{ width: '125px' }}
|
|
suffix='mm/s²'
|
|
onChange={(value) => setMaxAcceleration(value)}
|
|
onPressEnter={handleSetMaxAcceleration}
|
|
size='small'
|
|
/>
|
|
<Button
|
|
type='default'
|
|
style={{ width: 40 }}
|
|
onClick={handleSetMaxAcceleration}
|
|
>
|
|
Set
|
|
</Button>
|
|
</Space.Compact>
|
|
</Space>
|
|
</Space>
|
|
|
|
<Space direction='vertical' style={{ width: '100%' }}>
|
|
<Space direction='horizontal'>
|
|
<Text>Sqr Corner Vel:</Text>
|
|
<Space.Compact block size='small'>
|
|
<InputNumber
|
|
value={round(squareCornerVelocity, 2) || 0}
|
|
min={0.1}
|
|
max={1000}
|
|
step={0.1}
|
|
suffix='mm/s'
|
|
style={{ width: '125px' }}
|
|
onChange={(value) => setSquareCornerVelocity(value)}
|
|
onPressEnter={handleSetSquareCornerVelocity}
|
|
size='small'
|
|
/>
|
|
<Button
|
|
type='default'
|
|
style={{ width: 40 }}
|
|
onClick={handleSetSquareCornerVelocity}
|
|
>
|
|
Set
|
|
</Button>
|
|
</Space.Compact>
|
|
</Space>
|
|
</Space>
|
|
|
|
<Space direction='vertical' style={{ width: '100%' }}>
|
|
<Space direction='horizontal'>
|
|
<Text>Min Cruise Ratio:</Text>
|
|
<Space.Compact block size='small'>
|
|
<InputNumber
|
|
value={round(minCruiseRatio * 100, 2) || 0}
|
|
min={0}
|
|
max={100}
|
|
step={1}
|
|
suffix='%'
|
|
style={{ width: '125px' }}
|
|
onChange={(value) => setMinCruiseRatio(value / 100)}
|
|
onPressEnter={handleSetMinCruiseRatio}
|
|
size='small'
|
|
/>
|
|
<Button
|
|
type='default'
|
|
style={{ width: 40 }}
|
|
onClick={handleSetMinCruiseRatio}
|
|
>
|
|
Set
|
|
</Button>
|
|
</Space.Compact>
|
|
</Space>
|
|
</Space>
|
|
</Space>
|
|
</>
|
|
)}
|
|
<Text>Homing Origin:</Text>
|
|
<Descriptions
|
|
column={1}
|
|
size='small'
|
|
bordered
|
|
style={{ flexGrow: 1 }}
|
|
styles={{ label: { width: '40px' } }}
|
|
>
|
|
<Descriptions.Item label='X' span={1}>
|
|
{round(positionData.homingOrigin[0], 2)}mm
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label='Y' span={1}>
|
|
{round(positionData.homingOrigin[1], 2)}mm
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label='Z' span={1}>
|
|
{round(positionData.homingOrigin[2], 2)}mm
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label='E'>
|
|
{round(positionData.homingOrigin[3], 2)}mm
|
|
</Descriptions.Item>
|
|
</Descriptions>
|
|
</Flex>
|
|
</>
|
|
)
|
|
}
|
|
]
|
|
|
|
return (
|
|
<div style={{ minWidth: 190 }}>
|
|
{positionData ? (
|
|
<Flex vertical gap='middle'>
|
|
<Flex vertical gap={'middle'}>
|
|
<Descriptions
|
|
column={1}
|
|
size='small'
|
|
bordered
|
|
styles={{ label: { width: '40px' } }}
|
|
>
|
|
<Descriptions.Item label='X'>
|
|
<Space>
|
|
<Text>{round(positionData.livePosition[0], 2)}mm</Text>
|
|
<Text type='secondary'>
|
|
{round(positionData.toolheadPosition[0], 2)}mm
|
|
</Text>
|
|
</Space>
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label='Y'>
|
|
<Space>
|
|
<Text>{round(positionData.livePosition[1], 2)}mm</Text>
|
|
<Text type='secondary'>
|
|
{round(positionData.toolheadPosition[1], 2)}mm
|
|
</Text>
|
|
</Space>
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label='Z'>
|
|
<Space>
|
|
<Text>{round(positionData.livePosition[2], 2)}mm</Text>
|
|
<Text type='secondary'>
|
|
{round(positionData.toolheadPosition[2], 2)}mm
|
|
</Text>
|
|
</Space>
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label='E'>
|
|
<Space>
|
|
<Text>{round(positionData.livePosition[3], 2)}mm</Text>
|
|
<Text type='secondary'>
|
|
{round(positionData.toolheadPosition[3], 2)}mm
|
|
</Text>
|
|
</Space>
|
|
</Descriptions.Item>
|
|
</Descriptions>
|
|
{showControls && (
|
|
<>
|
|
<Space direction='vertical' style={{ width: '100%' }}>
|
|
<Space direction='horizontal'>
|
|
<Text>Speed Factor:</Text>
|
|
<Space.Compact block size='small'>
|
|
<InputNumber
|
|
value={round(speedFactor, 2)}
|
|
min={0.1}
|
|
max={2}
|
|
step={0.1}
|
|
style={{ width: '125px' }}
|
|
suffix='%'
|
|
onChange={(value) => setSpeedFactor(value)}
|
|
onPressEnter={handleSetSpeedFactor}
|
|
size='small'
|
|
/>
|
|
<Button
|
|
type='default'
|
|
style={{ width: 40 }}
|
|
onClick={handleSetSpeedFactor}
|
|
>
|
|
Set
|
|
</Button>
|
|
</Space.Compact>
|
|
</Space>
|
|
|
|
<Space direction='horizontal'>
|
|
<Text>Extrude Factor:</Text>
|
|
<Space.Compact block size='small'>
|
|
<InputNumber
|
|
value={round(extrudeFactor, 2)}
|
|
min={0.1}
|
|
max={2}
|
|
step={0.1}
|
|
style={{ width: '125px' }}
|
|
suffix='%'
|
|
onChange={(value) => setExtrudeFactor(value)}
|
|
onPressEnter={handleSetExtrudeFactor}
|
|
size='small'
|
|
/>
|
|
<Button
|
|
type='default'
|
|
style={{ width: 40 }}
|
|
onClick={handleSetExtrudeFactor}
|
|
>
|
|
Set
|
|
</Button>
|
|
</Space.Compact>
|
|
</Space>
|
|
</Space>
|
|
</>
|
|
)}
|
|
<Descriptions
|
|
column={1}
|
|
size='small'
|
|
bordered
|
|
styles={{ label: { width: '125px' } }}
|
|
>
|
|
<Descriptions.Item label='Speed'>
|
|
{round(positionData.speed, 2)}mm/s
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label='Abs Coor'>
|
|
{positionData ? (
|
|
<BoolDisplay
|
|
value={positionData.absoluteCoordinates}
|
|
yesNo={true}
|
|
/>
|
|
) : (
|
|
<Text>n/a</Text>
|
|
)}
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label='Abs Extrude'>
|
|
{positionData ? (
|
|
<BoolDisplay
|
|
value={positionData.absoluteExtrude}
|
|
yesNo={true}
|
|
/>
|
|
) : (
|
|
<Text>n/a</Text>
|
|
)}
|
|
</Descriptions.Item>
|
|
</Descriptions>
|
|
</Flex>
|
|
|
|
{showMoreInfo && (
|
|
<CustomCollapse
|
|
ghost
|
|
size='small'
|
|
items={moreInfoItems}
|
|
expandIcon={({ isActive }) => (
|
|
<CaretRightOutlined rotate={isActive ? 90 : 0} />
|
|
)}
|
|
/>
|
|
)}
|
|
</Flex>
|
|
) : (
|
|
<Flex justify='centre'>
|
|
<Spin indicator={<LoadingOutlined spin />} size='large' />
|
|
</Flex>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
PrinterPositionPanel.propTypes = {
|
|
id: PropTypes.string.isRequired,
|
|
showControls: PropTypes.bool,
|
|
showMoreInfo: PropTypes.bool
|
|
}
|
|
|
|
export default PrinterPositionPanel
|