ladder-logic-luminary / index.html
Wantomo's picture
please create electrical drawing single line diagram simulator
a3588cc verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PLC Logic Simulator</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/feather-icons"></script>
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
<style>
.ladder-rung {
height: 80px;
border-left: 4px solid #4B5563;
border-right: 4px solid #4B5563;
position: relative;
}
.ladder-rail {
width: 100%;
height: 4px;
background-color: #4B5563;
}
.contact {
width: 40px;
height: 40px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.3s ease;
}
.contact.active {
background-color: #10B981;
}
.contact.inactive {
background-color: #EF4444;
}
.coil {
width: 50px;
height: 30px;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.3s ease;
}
.coil.active {
background-color: #10B981;
}
.coil.inactive {
background-color: #EF4444;
}
.wire {
height: 4px;
background-color: #4B5563;
}
.logic-gate {
width: 60px;
height: 60px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 8px;
cursor: pointer;
transition: all 0.3s ease;
}
.logic-gate.active {
background-color: #10B981;
}
.logic-gate.inactive {
background-color: #EF4444;
}
</style>
</head>
<body class="bg-gray-100 min-h-screen">
<div class="container mx-auto px-4 py-8">
<header class="mb-8 text-center">
<h1 class="text-4xl font-bold text-gray-800 mb-2">Industrial Control Simulators</h1>
<p class="text-gray-600">Drag, drop, and simulate industrial control systems</p>
<div class="mt-4 flex justify-center space-x-4">
<a href="index.html" class="px-4 py-2 bg-blue-500 text-white rounded-lg">PLC Simulator</a>
<a href="singleline.html" class="px-4 py-2 bg-green-500 text-white rounded-lg">Single Line Diagram</a>
</div>
</header>
<div class="grid grid-cols-1 lg:grid-cols-4 gap-6 mt-8">
<!-- Toolbox -->
<div class="bg-white rounded-lg shadow-md p-4 lg:col-span-1">
<h2 class="text-xl font-semibold mb-4 text-gray-800">Components</h2>
<div class="space-y-3">
<div class="bg-gray-100 p-3 rounded-lg flex items-center cursor-move" draggable="true" data-type="contact-normally-open">
<i data-feather="circle" class="text-gray-700 mr-2"></i>
<span>NO Contact</span>
</div>
<div class="bg-gray-100 p-3 rounded-lg flex items-center cursor-move" draggable="true" data-type="contact-normally-closed">
<i data-feather="x" class="text-gray-700 mr-2"></i>
<span>NC Contact</span>
</div>
<div class="bg-gray-100 p-3 rounded-lg flex items-center cursor-move" draggable="true" data-type="coil">
<i data-feather="square" class="text-gray-700 mr-2"></i>
<span>Coil</span>
</div>
<div class="bg-gray-100 p-3 rounded-lg flex items-center cursor-move" draggable="true" data-type="timer">
<i data-feather="clock" class="text-gray-700 mr-2"></i>
<span>Timer</span>
</div>
<div class="bg-gray-100 p-3 rounded-lg flex items-center cursor-move" draggable="true" data-type="counter">
<i data-feather="hash" class="text-gray-700 mr-2"></i>
<span>Counter</span>
</div>
</div>
</div>
<!-- Workspace -->
<div class="bg-white rounded-lg shadow-md p-4 lg:col-span-3" id="workspace">
<div class="flex justify-between items-center mb-4">
<h2 class="text-xl font-semibold text-gray-800">Ladder Diagram</h2>
<div class="flex space-x-2">
<button class="bg-green-500 hover:bg-green-600 text-white px-4 py-2 rounded-lg flex items-center">
<i data-feather="play" class="mr-2"></i>
Run
</button>
<button class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg flex items-center">
<i data-feather="save" class="mr-2"></i>
Save
</button>
<button class="bg-red-500 hover:bg-red-600 text-white px-4 py-2 rounded-lg flex items-center">
<i data-feather="trash-2" class="mr-2"></i>
Clear
</button>
</div>
</div>
<div class="border-2 border-gray-300 rounded-lg p-6 min-h-[500px]" id="ladder-diagram">
<!-- Vertical rails -->
<div class="flex justify-between mb-4">
<div class="w-12 h-full border-r-2 border-gray-400"></div>
<div class="w-12 h-full border-l-2 border-gray-400"></div>
</div>
<!-- Rung 1 -->
<div class="relative mb-8">
<div class="ladder-rail"></div>
<div class="ladder-rung flex items-center justify-center px-12">
<div class="contact inactive" data-type="contact-normally-open" data-id="1"></div>
<div class="wire w-16"></div>
<div class="coil inactive" data-type="coil" data-id="1"></div>
</div>
<div class="ladder-rail"></div>
</div>
<!-- Rung 2 -->
<div class="relative mb-8">
<div class="ladder-rail"></div>
<div class="ladder-rung flex items-center justify-center px-12">
<div class="contact inactive" data-type="contact-normally-closed" data-id="2"></div>
<div class="wire w-16"></div>
<div class="contact inactive" data-type="contact-normally-open" data-id="3"></div>
<div class="wire w-16"></div>
<div class="coil inactive" data-type="coil" data-id="2"></div>
</div>
<div class="ladder-rail"></div>
</div>
<!-- Empty rung template (hidden) -->
<div class="hidden" id="rung-template">
<div class="relative mb-8">
<div class="ladder-rail"></div>
<div class="ladder-rung flex items-center justify-center px-12"></div>
<div class="ladder-rail"></div>
</div>
</div>
</div>
<div class="mt-4 flex justify-center">
<button id="add-rung" class="bg-gray-200 hover:bg-gray-300 text-gray-800 px-4 py-2 rounded-lg flex items-center">
<i data-feather="plus" class="mr-2"></i>
Add Rung
</button>
</div>
</div>
</div>
<div class="mt-8 bg-white rounded-lg shadow-md p-4">
<h2 class="text-xl font-semibold mb-4 text-gray-800">I/O Monitor</h2>
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
<div class="bg-gray-100 p-4 rounded-lg">
<div class="flex justify-between items-center">
<span>Input 1</span>
<div class="w-4 h-4 rounded-full bg-red-500 toggle-input" data-id="1"></div>
</div>
</div>
<div class="bg-gray-100 p-4 rounded-lg">
<div class="flex justify-between items-center">
<span>Input 2</span>
<div class="w-4 h-4 rounded-full bg-red-500 toggle-input" data-id="2"></div>
</div>
</div>
<div class="bg-gray-100 p-4 rounded-lg">
<div class="flex justify-between items-center">
<span>Output 1</span>
<div class="w-4 h-4 rounded-full bg-red-500" id="output-1"></div>
</div>
</div>
<div class="bg-gray-100 p-4 rounded-lg">
<div class="flex justify-between items-center">
<span>Output 2</span>
<div class="w-4 h-4 rounded-full bg-red-500" id="output-2"></div>
</div>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
feather.replace();
// Simple simulation logic
const toggleInputs = document.querySelectorAll('.toggle-input');
const contacts = document.querySelectorAll('[data-type^="contact"]');
const coils = document.querySelectorAll('[data-type="coil"]');
const outputs = [document.getElementById('output-1'), document.getElementById('output-2')];
toggleInputs.forEach(input => {
input.addEventListener('click', function() {
const isActive = this.classList.contains('bg-green-500');
this.classList.toggle('bg-green-500', !isActive);
this.classList.toggle('bg-red-500', isActive);
updateSimulation();
});
});
function updateSimulation() {
// Get input states
const input1 = toggleInputs[0].classList.contains('bg-green-500');
const input2 = toggleInputs[1].classList.contains('bg-green-500');
// Update contacts based on inputs
contacts.forEach(contact => {
const id = contact.dataset.id;
if (contact.dataset.type === 'contact-normally-open') {
if ((id === '1' && input1) || (id === '3' && input2)) {
contact.classList.add('active');
contact.classList.remove('inactive');
} else {
contact.classList.add('inactive');
contact.classList.remove('active');
}
} else if (contact.dataset.type === 'contact-normally-closed') {
if ((id === '2' && !input1)) {
contact.classList.add('active');
contact.classList.remove('inactive');
} else {
contact.classList.add('inactive');
contact.classList.remove('active');
}
}
});
// Calculate outputs
const output1 = document.querySelector('[data-id="1"].active') !== null;
const output2 = document.querySelector('[data-id="2"].active') !== null &&
document.querySelector('[data-id="3"].active') !== null;
// Update coils and outputs
coils.forEach(coil => {
const id = coil.dataset.id;
if ((id === '1' && output1) || (id === '2' && output2)) {
coil.classList.add('active');
coil.classList.remove('inactive');
} else {
coil.classList.add('inactive');
coil.classList.remove('active');
}
});
// Update output indicators
outputs[0].classList.toggle('bg-green-500', output1);
outputs[0].classList.toggle('bg-red-500', !output1);
outputs[1].classList.toggle('bg-green-500', output2);
outputs[1].classList.toggle('bg-red-500', !output2);
}
// Add new rung
document.getElementById('add-rung').addEventListener('click', function() {
const template = document.getElementById('rung-template');
const newRung = template.cloneNode(true);
newRung.classList.remove('hidden');
document.getElementById('ladder-diagram').appendChild(newRung);
});
// Simple drag and drop (placeholder functionality)
const draggables = document.querySelectorAll('[draggable="true"]');
const workspace = document.getElementById('workspace');
draggables.forEach(draggable => {
draggable.addEventListener('dragstart', function(e) {
e.dataTransfer.setData('text/plain', this.dataset.type);
});
});
workspace.addEventListener('dragover', function(e) {
e.preventDefault();
});
workspace.addEventListener('drop', function(e) {
e.preventDefault();
const type = e.dataTransfer.getData('text/plain');
// In a real implementation, you would create a new component at the drop position
alert(`Dropped ${type} component. In a full implementation, this would create a new ${type} on the ladder diagram.`);
});
});
</script>
<script>feather.replace();</script>
</body>
</html>