Files
3d_Kalibrasyon/old/index.html
2025-11-09 17:24:14 +03:00

414 lines
22 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3D Yazıcı Kalibrasyon</title>
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; }
/* Utility Classes */
.min-h-screen { min-height: 100vh; }
.bg-gradient { background: linear-gradient(135deg, #0f172a 0%, #1e293b 50%, #0f172a 100%); }
.text-white { color: white; }
.p-4 { padding: 1rem; }
.max-w-6xl { max-width: 72rem; }
.mx-auto { margin-left: auto; margin-right: auto; }
.text-center { text-align: center; }
.mb-2 { margin-bottom: 0.5rem; }
.mb-4 { margin-bottom: 1rem; }
.mb-6 { margin-bottom: 1.5rem; }
.mb-8 { margin-bottom: 2rem; }
.mt-1 { margin-top: 0.25rem; }
.mt-2 { margin-top: 0.5rem; }
.mt-4 { margin-top: 1rem; }
.mt-6 { margin-top: 1.5rem; }
.text-4xl { font-size: 2.25rem; line-height: 2.5rem; }
.text-2xl { font-size: 1.5rem; line-height: 2rem; }
.text-xl { font-size: 1.25rem; line-height: 1.75rem; }
.text-lg { font-size: 1.125rem; line-height: 1.75rem; }
.text-sm { font-size: 0.875rem; line-height: 1.25rem; }
.text-xs { font-size: 0.75rem; line-height: 1rem; }
.font-bold { font-weight: 700; }
.font-semibold { font-weight: 600; }
.bg-slate-800 { background-color: rgba(30, 41, 59, 0.5); }
.bg-slate-700 { background-color: #334155; }
.bg-slate-900 { background-color: #0f172a; }
.text-slate-400 { color: #94a3b8; }
.text-slate-500 { color: #64748b; }
.text-slate-300 { color: #cbd5e1; }
.text-cyan-400 { color: #22d3ee; }
.text-cyan-300 { color: #67e8f9; }
.text-blue-400 { color: #60a5fa; }
.text-blue-300 { color: #93c5fd; }
.text-green-400 { color: #4ade80; }
.text-yellow-400 { color: #facc15; }
.text-yellow-300 { color: #fde047; }
.border { border-width: 1px; }
.border-slate-700 { border-color: #334155; }
.border-slate-600 { border-color: #475569; }
.rounded { border-radius: 0.25rem; }
.rounded-lg { border-radius: 0.5rem; }
.px-3 { padding-left: 0.75rem; padding-right: 0.75rem; }
.px-4 { padding-left: 1rem; padding-right: 1rem; }
.px-6 { padding-left: 1.5rem; padding-right: 1.5rem; }
.py-2 { padding-top: 0.5rem; padding-bottom: 0.5rem; }
.py-3 { padding-top: 0.75rem; padding-bottom: 0.75rem; }
.p-4 { padding: 1rem; }
.p-6 { padding: 1.5rem; }
.w-full { width: 100%; }
.flex { display: flex; }
.items-center { align-items: center; }
.justify-between { justify-content: space-between; }
.gap-2 { gap: 0.5rem; }
.gap-4 { gap: 1rem; }
.grid { display: grid; }
.grid-cols-1 { grid-template-columns: repeat(1, minmax(0, 1fr)); }
.overflow-x-auto { overflow-x: auto; }
.whitespace-nowrap { white-space: nowrap; }
.shadow-lg { box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1); }
.cursor-pointer { cursor: pointer; }
.transition-all { transition: all 0.3s; }
.backdrop-blur { backdrop-filter: blur(8px); }
.block { display: block; }
.space-y-1 > * + * { margin-top: 0.25rem; }
.space-y-3 > * + * { margin-top: 0.75rem; }
.list-decimal { list-style-type: decimal; }
.list-inside { list-style-position: inside; }
.ml-4 { margin-left: 1rem; }
.overflow-x-auto::-webkit-scrollbar { height: 8px; }
.overflow-x-auto::-webkit-scrollbar-track { background: #1e293b; }
.overflow-x-auto::-webkit-scrollbar-thumb { background: #334155; border-radius: 4px; }
.bg-gradient-cyan { background: linear-gradient(135deg, #06b6d4 0%, #3b82f6 100%); }
.bg-cyan-10 { background-color: rgba(34, 211, 238, 0.1); }
.border-cyan-30 { border-color: rgba(34, 211, 238, 0.3); }
.bg-blue-10 { background-color: rgba(96, 165, 250, 0.1); }
.border-blue-30 { border-color: rgba(96, 165, 250, 0.3); }
input[type="number"] {
-moz-appearance: textfield;
color: white;
}
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
button:hover {
transform: translateY(-2px);
box-shadow: 0 20px 25px -5px rgba(6, 182, 212, 0.3);
}
.tab-active {
background: linear-gradient(135deg, #06b6d4 0%, #3b82f6 100%);
color: white;
}
.tab-inactive {
background-color: rgba(30, 41, 59, 0.5);
color: #94a3b8;
}
.tab-inactive:hover {
background-color: #334155;
}
pre {
white-space: pre-wrap;
word-wrap: break-word;
font-family: 'Courier New', monospace;
}
code {
background-color: #0f172a;
padding: 0.125rem 0.5rem;
border-radius: 0.25rem;
}
@media (min-width: 768px) {
.md\\:grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.md\\:flex-row { flex-direction: row; }
}
@media (max-width: 767px) {
.flex-col { flex-direction: column; }
}
</style>
</head>
<body>
<div id="root"></div>
<script>
const { useState, createElement: e } = React;
// Icon components (simplified versions)
const Download = () => e('svg', { width: 20, height: 20, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2 },
e('path', { d: 'M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3' }));
const Settings = () => e('svg', { width: 20, height: 20, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2 },
e('circle', { cx: 12, cy: 12, r: 3 }),
e('path', { d: 'M12 1v6m0 6v6m8.66-10a9 9 0 1 1-17.32 0' }));
const Move = () => e('svg', { width: 18, height: 18, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2 },
e('polyline', { points: '5 9 2 12 5 15' }),
e('polyline', { points: '9 5 12 2 15 5' }),
e('polyline', { points: '15 19 12 22 9 19' }),
e('polyline', { points: '19 9 22 12 19 15' }),
e('line', { x1: 2, y1: 12, x2: 22, y2: 12 }),
e('line', { x1: 12, y1: 2, x2: 12, y2: 22 }));
const Box = () => e('svg', { width: 18, height: 18, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2 },
e('path', { d: 'M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z' }),
e('polyline', { points: '3.27 6.96 12 12.01 20.73 6.96' }),
e('line', { x1: 12, y1: 22.08, x2: 12, y2: 12 }));
const Maximize2 = () => e('svg', { width: 18, height: 18, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2 },
e('polyline', { points: '15 3 21 3 21 9' }),
e('polyline', { points: '9 21 3 21 3 15' }),
e('line', { x1: 21, y1: 3, x2: 14, y2: 10 }),
e('line', { x1: 3, y1: 21, x2: 10, y2: 14 }));
function PrinterCalibration() {
const [activeTab, setActiveTab] = useState('x-axis');
const [settings, setSettings] = useState({
bedTemp: 60,
nozzleTemp: 200,
nozzleDiameter: 0.4
});
const [xAxisConfig, setXAxisConfig] = useState({ distance: 100, steps: 80, measured: 0 });
const [yAxisConfig, setYAxisConfig] = useState({ distance: 100, steps: 80, measured: 0 });
const [zAxisConfig, setZAxisConfig] = useState({ distance: 10, steps: 400, measured: 0 });
const [extruderConfig, setExtruderConfig] = useState({ distance: 100, steps: 93, measured: 0 });
const [skewConfig, setSkewConfig] = useState({ ac: 141.4, bd: 141.4, ad: 141.4 });
const calculateSteps = (config) => {
if (config.measured > 0) {
return ((config.distance / config.measured) * config.steps).toFixed(2);
}
return config.steps;
};
const calculateSkew = () => {
const ac = parseFloat(skewConfig.ac);
const bd = parseFloat(skewConfig.bd);
const ad = parseFloat(skewConfig.ad);
if (ac > 0 && bd > 0 && ad > 0) {
return {
xy: (Math.atan2(ac - 141.4, 100) * (180 / Math.PI)).toFixed(4),
xz: (Math.atan2(bd - 141.4, 100) * (180 / Math.PI)).toFixed(4),
yz: (Math.atan2(ad - 141.4, 100) * (180 / Math.PI)).toFixed(4)
};
}
return { xy: '0.0000', xz: '0.0000', yz: '0.0000' };
};
const generateGCode = () => {
let gcode = '; 3D Yazıcı Kalibrasyon G-Code\n';
gcode += '; Oluşturma Tarihi: ' + new Date().toLocaleString('tr-TR') + '\n\n';
gcode += `M140 S${settings.bedTemp}\nM104 S${settings.nozzleTemp}\n`;
gcode += `M190 S${settings.bedTemp}\nM109 S${settings.nozzleTemp}\n\n`;
const configs = { 'x-axis': xAxisConfig, 'y-axis': yAxisConfig, 'z-axis': zAxisConfig, 'extruder': extruderConfig };
const axes = { 'x-axis': 'X', 'y-axis': 'Y', 'z-axis': 'Z', 'extruder': 'E' };
if (activeTab === 'skew') {
const skew = calculateSkew();
gcode += `M852 I${skew.xy} J${skew.xz} K${skew.yz}\nM500\n`;
} else {
const config = configs[activeTab];
const axis = axes[activeTab];
gcode += 'G28\nG90\n';
if (activeTab === 'extruder') {
gcode += `M82\nG92 E0\nG1 E${config.distance} F100\n`;
} else {
if (activeTab !== 'z-axis') gcode += 'G1 Z10 F3000\n';
gcode += `G1 ${axis}${config.distance} F${activeTab === 'z-axis' ? '300' : '3000'}\n`;
}
gcode += `M400\n; M92 ${axis}${calculateSteps(config)}\n; M500\n`;
}
gcode += '\nM104 S0\nM140 S0\nG28 X Y\nM84\n';
return gcode;
};
const downloadGCode = () => {
const blob = new Blob([generateGCode()], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `calibration_${activeTab}_${Date.now()}.gcode`;
a.click();
URL.revokeObjectURL(url);
};
const tabs = [
{ id: 'x-axis', name: 'X Ekseni', icon: Move },
{ id: 'y-axis', name: 'Y Ekseni', icon: Move },
{ id: 'z-axis', name: 'Z Ekseni', icon: Move },
{ id: 'extruder', name: 'Extruder', icon: Box },
{ id: 'skew', name: 'Çarpıklık', icon: Maximize2 }
];
const renderAxisCalibration = (config, setConfig, axis) => {
return e('div', null,
e('h3', { className: 'text-2xl font-semibold mb-4 text-cyan-400' }, `${axis} Ekseni Kalibrasyonu`),
e('div', { className: 'grid grid-cols-1 md:grid-cols-3 gap-4 mb-6' },
e('div', null,
e('label', { className: 'block text-sm text-slate-400 mb-1' }, 'Hedef Mesafe (mm)'),
e('input', {
type: 'number',
value: config.distance,
onChange: (ev) => setConfig({...config, distance: parseInt(ev.target.value)}),
className: 'w-full bg-slate-700 border border-slate-600 rounded px-3 py-2'
})
),
e('div', null,
e('label', { className: 'block text-sm text-slate-400 mb-1' }, 'Mevcut Steps/mm'),
e('input', {
type: 'number',
step: '0.01',
value: config.steps,
onChange: (ev) => setConfig({...config, steps: parseFloat(ev.target.value)}),
className: 'w-full bg-slate-700 border border-slate-600 rounded px-3 py-2'
})
),
e('div', null,
e('label', { className: 'block text-sm text-slate-400 mb-1' }, 'Ölçülen Mesafe (mm)'),
e('input', {
type: 'number',
step: '0.01',
value: config.measured,
onChange: (ev) => setConfig({...config, measured: parseFloat(ev.target.value)}),
className: 'w-full bg-slate-700 border border-slate-600 rounded px-3 py-2',
placeholder: 'Test sonrası giriniz'
})
)
),
config.measured > 0 && e('div', { className: 'bg-cyan-10 border border-cyan-30 rounded-lg p-4' },
e('h4', { className: 'font-semibold text-cyan-400 mb-2' }, 'Hesaplanan Değer:'),
e('p', { className: 'text-2xl font-bold text-cyan-300' }, `${calculateSteps(config)} steps/mm`)
)
);
};
return e('div', { className: 'min-h-screen bg-gradient text-white p-4' },
e('div', { className: 'max-w-6xl mx-auto' },
e('div', { className: 'text-center mb-8' },
e('h1', { className: 'text-4xl font-bold mb-2', style: { background: 'linear-gradient(135deg, #22d3ee 0%, #3b82f6 100%)', WebkitBackgroundClip: 'text', WebkitTextFillColor: 'transparent' } },
'3D Yazıcı Kalibrasyon'
),
e('p', { className: 'text-slate-400' }, 'Profesyonel Kalibrasyon ve G-code Üretici')
),
e('div', { className: 'bg-slate-800 backdrop-blur rounded-lg p-6 mb-6 border border-slate-700' },
e('div', { className: 'flex items-center gap-2 mb-4' },
e(Settings),
e('h2', { className: 'text-xl font-semibold' }, 'Genel Ayarlar')
),
e('div', { className: 'grid grid-cols-1 md:grid-cols-3 gap-4' },
e('div', null,
e('label', { className: 'block text-sm text-slate-400 mb-1' }, 'Tabla Sıcaklığı (°C)'),
e('input', {
type: 'number',
value: settings.bedTemp,
onChange: (ev) => setSettings({...settings, bedTemp: parseInt(ev.target.value)}),
className: 'w-full bg-slate-700 border border-slate-600 rounded px-3 py-2'
})
),
e('div', null,
e('label', { className: 'block text-sm text-slate-400 mb-1' }, 'Nozzle Sıcaklığı (°C)'),
e('input', {
type: 'number',
value: settings.nozzleTemp,
onChange: (ev) => setSettings({...settings, nozzleTemp: parseInt(ev.target.value)}),
className: 'w-full bg-slate-700 border border-slate-600 rounded px-3 py-2'
})
),
e('div', null,
e('label', { className: 'block text-sm text-slate-400 mb-1' }, 'Nozzle Çapı (mm)'),
e('input', {
type: 'number',
step: '0.1',
value: settings.nozzleDiameter,
onChange: (ev) => setSettings({...settings, nozzleDiameter: parseFloat(ev.target.value)}),
className: 'w-full bg-slate-700 border border-slate-600 rounded px-3 py-2'
})
)
)
),
e('div', { className: 'flex gap-2 mb-6 overflow-x-auto' },
tabs.map(tab => e('button', {
key: tab.id,
onClick: () => setActiveTab(tab.id),
className: `flex items-center gap-2 px-4 py-3 rounded-lg transition-all whitespace-nowrap ${activeTab === tab.id ? 'tab-active shadow-lg' : 'tab-inactive'}`
},
e(tab.icon),
tab.name
))
),
e('div', { className: 'bg-slate-800 backdrop-blur rounded-lg p-6 border border-slate-700 mb-6' },
activeTab === 'x-axis' && renderAxisCalibration(xAxisConfig, setXAxisConfig, 'X'),
activeTab === 'y-axis' && renderAxisCalibration(yAxisConfig, setYAxisConfig, 'Y'),
activeTab === 'z-axis' && renderAxisCalibration(zAxisConfig, setZAxisConfig, 'Z'),
activeTab === 'extruder' && renderAxisCalibration(extruderConfig, setExtruderConfig, 'Extruder'),
activeTab === 'skew' && e('div', null,
e('h3', { className: 'text-2xl font-semibold mb-4 text-cyan-400' }, 'Çarpıklık Kalibrasyonu'),
e('div', { className: 'grid grid-cols-1 md:grid-cols-3 gap-4 mb-6' },
['ac', 'bd', 'ad'].map((key, idx) => e('div', { key },
e('label', { className: 'block text-sm text-slate-400 mb-1' }, ['AC Köşegeni (mm)', 'BD Köşegeni (mm)', 'AD Köşegeni (mm)'][idx]),
e('input', {
type: 'number',
step: '0.01',
value: skewConfig[key],
onChange: (ev) => setSkewConfig({...skewConfig, [key]: ev.target.value}),
className: 'w-full bg-slate-700 border border-slate-600 rounded px-3 py-2'
})
))
),
e('div', { className: 'bg-cyan-10 border border-cyan-30 rounded-lg p-4' },
e('h4', { className: 'font-semibold text-cyan-400 mb-3' }, 'Hesaplanan Çarpıklık Değerleri:'),
e('div', { className: 'grid grid-cols-1 md:grid-cols-3 gap-4' },
['xy', 'xz', 'yz'].map(k => e('div', { key: k },
e('p', { className: 'text-sm text-slate-400' }, `${k.toUpperCase()} Çarpıklığı`),
e('p', { className: 'text-xl font-bold text-cyan-300' }, `${calculateSkew()[k]}°`)
))
)
)
)
),
e('div', { className: 'bg-slate-800 backdrop-blur rounded-lg p-6 border border-slate-700' },
e('div', { className: 'flex flex-col md:flex-row items-center justify-between gap-4' },
e('div', null,
e('h3', { className: 'text-lg font-semibold mb-1' }, 'G-code Oluştur'),
e('p', { className: 'text-sm text-slate-400' }, 'Seçili kalibrasyon için G-code dosyası indir')
),
e('button', {
onClick: downloadGCode,
className: 'flex items-center gap-2 bg-gradient-cyan px-6 py-3 rounded-lg font-semibold transition-all shadow-lg cursor-pointer'
},
e(Download),
'G-code İndir'
)
),
e('div', { className: 'mt-6' },
e('h4', { className: 'text-sm font-semibold text-slate-400 mb-2' }, 'G-code Önizleme:'),
e('div', { className: 'bg-slate-900 rounded-lg p-4 overflow-x-auto' },
e('pre', { className: 'text-xs text-green-400' }, generateGCode())
)
)
)
)
);
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(e(PrinterCalibration));
</script>
</body>
</html>