Files
hmitestWinform/frontend/components/MotionPanel.tsx
LGram16 8dc6b0f921 Initial commit: Industrial HMI system with component architecture
- Implement WebView2-based HMI frontend with React + TypeScript + Vite
- Add C# .NET backend with WebSocket communication layer
- Separate UI components into modular structure:
  * RecipePanel: Recipe selection and management
  * IOPanel: I/O monitoring and control (32 inputs/outputs)
  * MotionPanel: Servo control for X/Y/Z axes
  * CameraPanel: Vision system feed with HUD overlay
  * SettingsModal: System configuration management
- Create reusable UI components (CyberPanel, TechButton, PanelHeader)
- Implement dual-mode communication (WebView2 native + WebSocket fallback)
- Add 3D visualization with Three.js/React Three Fiber
- Fix JSON parsing bug in configuration save handler
- Include comprehensive .gitignore for .NET and Node.js projects

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-24 20:40:45 +09:00

68 lines
3.5 KiB
TypeScript

import React, { useState } from 'react';
import { Move } from 'lucide-react';
import { RobotTarget, AxisPosition } from '../types';
import { PanelHeader } from './common/PanelHeader';
import { TechButton } from './common/TechButton';
const MOCK_POSITIONS: AxisPosition[] = [
{ id: 'p1', name: 'Home Position', axis: 'X', value: 0, speed: 100, acc: 100, dec: 100 },
{ id: 'p2', name: 'Pick Pos A', axis: 'X', value: -1.5, speed: 500, acc: 200, dec: 200 },
{ id: 'p3', name: 'Place Pos B', axis: 'X', value: 1.5, speed: 500, acc: 200, dec: 200 },
{ id: 'p4', name: 'Scan Index', axis: 'X', value: 0.5, speed: 300, acc: 100, dec: 100 },
{ id: 'py1', name: 'Rear Limit', axis: 'Y', value: -1.5, speed: 200, acc: 100, dec: 100 },
{ id: 'pz1', name: 'Safe Height', axis: 'Z', value: 0, speed: 50, acc: 50, dec: 50 },
];
interface MotionPanelProps {
robotTarget: RobotTarget;
onMove: (axis: 'X' | 'Y' | 'Z', val: number) => void;
}
export const MotionPanel: React.FC<MotionPanelProps> = ({ robotTarget, onMove }) => {
const [axis, setAxis] = useState<'X' | 'Y' | 'Z'>('X');
return (
<div className="h-full flex flex-col">
<PanelHeader title="Servo Control" icon={Move} />
<div className="flex gap-2 mb-4">
{['X', 'Y', 'Z'].map(a => (
<button
key={a}
onClick={() => setAxis(a as any)}
className={`flex-1 py-2 font-tech font-bold text-lg border-b-2 transition-all ${axis === a ? 'text-neon-blue border-neon-blue bg-neon-blue/10' : 'text-slate-500 border-slate-700 hover:text-slate-300'}`}
>
{a}-AXIS
</button>
))}
</div>
<div className="bg-black/40 p-4 rounded border border-white/10 mb-4 text-center">
<div className="text-[10px] text-slate-400 uppercase tracking-widest mb-1">Current Position</div>
<div className="font-mono text-3xl text-neon-blue text-shadow-glow-blue">
{robotTarget[axis.toLowerCase() as 'x' | 'y' | 'z'].toFixed(3)}
<span className="text-sm text-slate-500 ml-2">mm</span>
</div>
</div>
<div className="space-y-2 overflow-y-auto flex-1 pr-2 custom-scrollbar">
{MOCK_POSITIONS.filter(p => p.axis === axis).map(p => (
<div key={p.id} className="flex items-center justify-between p-3 bg-white/5 border border-white/5 hover:border-neon-blue/50 transition-all group">
<span className="text-xs font-bold text-slate-300 group-hover:text-white">{p.name}</span>
<button
onClick={() => onMove(axis, p.value)}
className="px-3 py-1 bg-slate-800 hover:bg-neon-blue hover:text-black text-xs font-mono transition-colors"
>
GO {p.value}
</button>
</div>
))}
</div>
<div className="flex gap-2 mt-4">
<TechButton className="flex-1 font-mono text-lg" onClick={() => onMove(axis, robotTarget[axis.toLowerCase() as 'x' | 'y' | 'z'] - 0.1)}>-</TechButton>
<TechButton className="flex-1 font-mono text-lg" onClick={() => onMove(axis, robotTarget[axis.toLowerCase() as 'x' | 'y' | 'z'] + 0.1)}>+</TechButton>
</div>
</div>
);
};