ladder-logic-luminary / singleline.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>Single Line Diagram Simulator</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/feather-icons"></script>
<style>
.workspace {
background-color: #f8fafc;
background-image: linear-gradient(#e2e8f0 1px, transparent 1px),
linear-gradient(90deg, #e2e8f0 1px, transparent 1px);
background-size: 20px 20px;
}
.component {
cursor: move;
transition: all 0.2s;
}
.component:hover {
filter: drop-shadow(0 0 4px rgba(0, 0, 0, 0.2));
}
.busbar {
height: 10px;
background-color: #4B5563;
}
.transformer {
width: 60px;
height: 60px;
position: relative;
}
.circuit-breaker {
width: 30px;
height: 30px;
}
.generator {
width: 60px;
height: 30px;
border-radius: 4px;
}
.load {
width: 40px;
height: 40px;
}
.wire {
stroke: #4B5563;
stroke-width: 2;
}
</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">Single Line Diagram Simulator</h1>
<p class="text-gray-600">Design and simulate electrical power systems</p>
</header>
<div class="grid grid-cols-1 lg:grid-cols-4 gap-6">
<!-- 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 flex-col items-center cursor-move component" draggable="true" data-type="busbar">
<svg width="60" height="10">
<rect width="60" height="10" fill="#4B5563" />
</svg>
<span class="mt-2">Busbar</span>
</div>
<div class="bg-gray-100 p-3 rounded-lg flex flex-col items-center cursor-move component" draggable="true" data-type="transformer">
<svg width="60" height="60" viewBox="0 0 60 60">
<rect x="10" y="10" width="40" height="40" fill="#F59E0B" />
<text x="30" y="35" text-anchor="middle" fill="white">T</text>
</svg>
<span class="mt-2">Transformer</span>
</div>
<div class="bg-gray-100 p-3 rounded-lg flex flex-col items-center cursor-move component" draggable="true" data-type="generator">
<svg width="60" height="30" viewBox="0 0 60 30">
<rect width="60" height="30" rx="4" fill="#10B981" />
<text x="30" y="18" text-anchor="middle" fill="white">G</text>
</svg>
<span class="mt-2">Generator</span>
</div>
<div class="bg-gray-100 p-3 rounded-lg flex flex-col items-center cursor-move component" draggable="true" data-type="circuit-breaker">
<svg width="30" height="30" viewBox="0 0 30 30">
<circle cx="15" cy="15" r="12" fill="#EF4444" />
<line x1="8" y1="8" x2="22" y2="22" stroke="white" stroke-width="2" />
</svg>
<span class="mt-2">Circuit Breaker</span>
</div>
<div class="bg-gray-100 p-3 rounded-lg flex flex-col items-center cursor-move component" draggable="true" data-type="load">
<svg width="40" height="40" viewBox="0 0 40 40">
<circle cx="20" cy="20" r="15" fill="#3B82F6" />
<text x="20" y="25" text-anchor="middle" fill="white">L</text>
</svg>
<span class="mt-2">Load</span>
</div>
</div>
</div>
<!-- Workspace -->
<div class="bg-white rounded-lg shadow-md p-4 lg:col-span-3">
<div class="flex justify-between items-center mb-4">
<h2 class="text-xl font-semibold text-gray-800">Diagram Workspace</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>
Simulate
</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="workspace border-2 border-gray-300 rounded-lg p-6 min-h-[500px]" id="diagram-workspace">
<svg id="diagram-svg" width="100%" height="100%"></svg>
</div>
</div>
</div>
<!-- Properties Panel -->
<div class="mt-8 bg-white rounded-lg shadow-md p-4">
<h2 class="text-xl font-semibold mb-4 text-gray-800">Component Properties</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label class="block text-gray-700 mb-2">Name</label>
<input type="text" class="w-full px-3 py-2 border border-gray-300 rounded-md" placeholder="Component name">
</div>
<div>
<label class="block text-gray-700 mb-2">Voltage (kV)</label>
<input type="number" class="w-full px-3 py-2 border border-gray-300 rounded-md" placeholder="11">
</div>
<div>
<label class="block text-gray-700 mb-2">Power (MVA)</label>
<input type="number" class="w-full px-3 py-2 border border-gray-300 rounded-md" placeholder="50">
</div>
<div>
<label class="block text-gray-700 mb-2">Status</label>
<select class="w-full px-3 py-2 border border-gray-300 rounded-md">
<option>Online</option>
<option>Offline</option>
<option>Fault</option>
</select>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
feather.replace();
const svg = document.getElementById('diagram-svg');
let selectedElement = null;
// Simple drag and drop
const components = document.querySelectorAll('[draggable="true"]');
const workspace = document.getElementById('diagram-workspace');
components.forEach(component => {
component.addEventListener('dragstart', function(e) {
e.dataTransfer.setData('type', this.dataset.type);
});
});
workspace.addEventListener('dragover', function(e) {
e.preventDefault();
});
workspace.addEventListener('drop', function(e) {
e.preventDefault();
const type = e.dataTransfer.getData('type');
const rect = workspace.getBoundingClientRect();
const x = e.clientX - rect.left - 30;
const y = e.clientY - rect.top - 30;
switch(type) {
case 'busbar':
createBusbar(x, y);
break;
case 'transformer':
createTransformer(x, y);
break;
case 'generator':
createGenerator(x, y);
break;
case 'circuit-breaker':
createCircuitBreaker(x, y);
break;
case 'load':
createLoad(x, y);
break;
}
});
function createBusbar(x, y) {
const busbar = document.createElementNS("http://www.w3.org/2000/svg", "rect");
busbar.setAttribute('x', x);
busbar.setAttribute('y', y);
busbar.setAttribute('width', '120');
busbar.setAttribute('height', '10');
busbar.setAttribute('fill', '#4B5563');
busbar.setAttribute('class', 'component');
busbar.addEventListener('click', selectElement);
svg.appendChild(busbar);
}
function createTransformer(x, y) {
const group = document.createElementNS("http://www.w3.org/2000/svg", "g");
group.setAttribute('transform', `translate(${x}, ${y})`);
const rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
rect.setAttribute('x', '10');
rect.setAttribute('y', '10');
rect.setAttribute('width', '40');
rect.setAttribute('height', '40');
rect.setAttribute('fill', '#F59E0B');
const text = document.createElementNS("http://www.w3.org/2000/svg", "text");
text.setAttribute('x', '30');
text.setAttribute('y', '35');
text.setAttribute('text-anchor', 'middle');
text.setAttribute('fill', 'white');
text.textContent = 'T';
group.appendChild(rect);
group.appendChild(text);
group.setAttribute('class', 'component');
group.addEventListener('click', selectElement);
svg.appendChild(group);
}
function createGenerator(x, y) {
const group = document.createElementNS("http://www.w3.org/2000/svg", "g");
group.setAttribute('transform', `translate(${x}, ${y})`);
const rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
rect.setAttribute('width', '60');
rect.setAttribute('height', '30');
rect.setAttribute('rx', '4');
rect.setAttribute('fill', '#10B981');
const text = document.createElementNS("http://www.w3.org/2000/svg", "text");
text.setAttribute('x', '30');
text.setAttribute('y', '18');
text.setAttribute('text-anchor', 'middle');
text.setAttribute('fill', 'white');
text.textContent = 'G';
group.appendChild(rect);
group.appendChild(text);
group.setAttribute('class', 'component');
group.addEventListener('click', selectElement);
svg.appendChild(group);
}
function createCircuitBreaker(x, y) {
const group = document.createElementNS("http://www.w3.org/2000/svg", "g");
group.setAttribute('transform', `translate(${x}, ${y})`);
const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
circle.setAttribute('cx', '15');
circle.setAttribute('cy', '15');
circle.setAttribute('r', '12');
circle.setAttribute('fill', '#EF4444');
const line = document.createElementNS("http://www.w3.org/2000/svg", "line");
line.setAttribute('x1', '8');
line.setAttribute('y1', '8');
line.setAttribute('x2', '22');
line.setAttribute('y2', '22');
line.setAttribute('stroke', 'white');
line.setAttribute('stroke-width', '2');
group.appendChild(circle);
group.appendChild(line);
group.setAttribute('class', 'component');
group.addEventListener('click', selectElement);
svg.appendChild(group);
}
function createLoad(x, y) {
const group = document.createElementNS("http://www.w3.org/2000/svg", "g");
group.setAttribute('transform', `translate(${x}, ${y})`);
const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
circle.setAttribute('cx', '20');
circle.setAttribute('cy', '20');
circle.setAttribute('r', '15');
circle.setAttribute('fill', '#3B82F6');
const text = document.createElementNS("http://www.w3.org/2000/svg", "text");
text.setAttribute('x', '20');
text.setAttribute('y', '25');
text.setAttribute('text-anchor', 'middle');
text.setAttribute('fill', 'white');
text.textContent = 'L';
group.appendChild(circle);
group.appendChild(text);
group.setAttribute('class', 'component');
group.addEventListener('click', selectElement);
svg.appendChild(group);
}
function selectElement(e) {
if (selectedElement) {
selectedElement.setAttribute('stroke', 'none');
}
selectedElement = e.target;
selectedElement.setAttribute('stroke', '#6366F1');
selectedElement.setAttribute('stroke-width', '2');
e.stopPropagation();
}
// Click on empty space to deselect
svg.addEventListener('click', function(e) {
if (e.target === svg && selectedElement) {
selectedElement.setAttribute('stroke', 'none');
selectedElement = null;
}
});
});
</script>
<script>feather.replace();</script>
</body>
</html>