Bbkblo commited on
Commit
b99f9fa
·
verified ·
1 Parent(s): 9285564

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +1166 -19
index.html CHANGED
@@ -1,19 +1,1166 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>CivilCAD - Engineering Drawing Application</title>
7
+ <style>
8
+ * {
9
+ margin: 0;
10
+ padding: 0;
11
+ box-sizing: border-box;
12
+ }
13
+
14
+ :root {
15
+ --bg-primary: #1e1e1e;
16
+ --bg-secondary: #252526;
17
+ --bg-tertiary: #2d2d30;
18
+ --bg-hover: #3e3e42;
19
+ --text-primary: #cccccc;
20
+ --text-secondary: #969696;
21
+ --accent: #007acc;
22
+ --accent-hover: #1e90ff;
23
+ --border: #3e3e42;
24
+ --success: #4ec9b0;
25
+ --warning: #ce9178;
26
+ --error: #f44747;
27
+ --grid-color: #2a2a2a;
28
+ --snap-color: #4a9eff;
29
+ }
30
+
31
+ body {
32
+ font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
33
+ background: var(--bg-primary);
34
+ color: var(--text-primary);
35
+ overflow: hidden;
36
+ user-select: none;
37
+ }
38
+
39
+ .app-container {
40
+ display: flex;
41
+ height: 100vh;
42
+ flex-direction: column;
43
+ }
44
+
45
+ /* Header */
46
+ .header {
47
+ background: var(--bg-secondary);
48
+ border-bottom: 1px solid var(--border);
49
+ padding: 8px 16px;
50
+ display: flex;
51
+ align-items: center;
52
+ justify-content: space-between;
53
+ min-height: 48px;
54
+ }
55
+
56
+ .header-left {
57
+ display: flex;
58
+ align-items: center;
59
+ gap: 20px;
60
+ }
61
+
62
+ .logo {
63
+ font-size: 20px;
64
+ font-weight: 600;
65
+ color: var(--accent);
66
+ display: flex;
67
+ align-items: center;
68
+ gap: 8px;
69
+ }
70
+
71
+ .logo::before {
72
+ content: "⚙";
73
+ font-size: 24px;
74
+ }
75
+
76
+ .header-nav {
77
+ display: flex;
78
+ gap: 4px;
79
+ }
80
+
81
+ .nav-btn {
82
+ padding: 6px 12px;
83
+ background: transparent;
84
+ color: var(--text-primary);
85
+ border: none;
86
+ cursor: pointer;
87
+ border-radius: 4px;
88
+ transition: all 0.2s;
89
+ font-size: 13px;
90
+ }
91
+
92
+ .nav-btn:hover {
93
+ background: var(--bg-hover);
94
+ }
95
+
96
+ /* Main Layout */
97
+ .main-content {
98
+ display: flex;
99
+ flex: 1;
100
+ overflow: hidden;
101
+ }
102
+
103
+ /* Toolbar */
104
+ .toolbar {
105
+ background: var(--bg-secondary);
106
+ width: 60px;
107
+ display: flex;
108
+ flex-direction: column;
109
+ align-items: center;
110
+ padding: 8px 0;
111
+ gap: 4px;
112
+ border-right: 1px solid var(--border);
113
+ }
114
+
115
+ .tool-btn {
116
+ width: 44px;
117
+ height: 44px;
118
+ background: transparent;
119
+ color: var(--text-secondary);
120
+ border: none;
121
+ cursor: pointer;
122
+ border-radius: 6px;
123
+ display: flex;
124
+ align-items: center;
125
+ justify-content: center;
126
+ font-size: 20px;
127
+ transition: all 0.2s;
128
+ position: relative;
129
+ }
130
+
131
+ .tool-btn:hover {
132
+ background: var(--bg-hover);
133
+ color: var(--text-primary);
134
+ }
135
+
136
+ .tool-btn.active {
137
+ background: var(--accent);
138
+ color: white;
139
+ }
140
+
141
+ .tool-tooltip {
142
+ position: absolute;
143
+ left: 54px;
144
+ background: var(--bg-tertiary);
145
+ padding: 4px 8px;
146
+ border-radius: 4px;
147
+ font-size: 12px;
148
+ white-space: nowrap;
149
+ pointer-events: none;
150
+ opacity: 0;
151
+ transition: opacity 0.2s;
152
+ z-index: 1000;
153
+ border: 1px solid var(--border);
154
+ }
155
+
156
+ .tool-btn:hover .tool-tooltip {
157
+ opacity: 1;
158
+ }
159
+
160
+ .tool-separator {
161
+ width: 30px;
162
+ height: 1px;
163
+ background: var(--border);
164
+ margin: 4px 0;
165
+ }
166
+
167
+ /* Canvas Area */
168
+ .canvas-container {
169
+ flex: 1;
170
+ background: var(--bg-primary);
171
+ position: relative;
172
+ overflow: hidden;
173
+ }
174
+
175
+ #drawingCanvas {
176
+ position: absolute;
177
+ top: 0;
178
+ left: 0;
179
+ cursor: crosshair;
180
+ }
181
+
182
+ .canvas-grid {
183
+ position: absolute;
184
+ top: 0;
185
+ left: 0;
186
+ pointer-events: none;
187
+ }
188
+
189
+ /* Properties Panel */
190
+ .properties-panel {
191
+ background: var(--bg-secondary);
192
+ width: 280px;
193
+ border-left: 1px solid var(--border);
194
+ display: flex;
195
+ flex-direction: column;
196
+ }
197
+
198
+ .panel-header {
199
+ padding: 12px 16px;
200
+ background: var(--bg-tertiary);
201
+ border-bottom: 1px solid var(--border);
202
+ font-size: 13px;
203
+ font-weight: 600;
204
+ display: flex;
205
+ align-items: center;
206
+ justify-content: space-between;
207
+ }
208
+
209
+ .panel-content {
210
+ flex: 1;
211
+ padding: 16px;
212
+ overflow-y: auto;
213
+ }
214
+
215
+ .property-group {
216
+ margin-bottom: 20px;
217
+ }
218
+
219
+ .property-label {
220
+ font-size: 12px;
221
+ color: var(--text-secondary);
222
+ margin-bottom: 6px;
223
+ text-transform: uppercase;
224
+ letter-spacing: 0.5px;
225
+ }
226
+
227
+ .property-row {
228
+ display: flex;
229
+ align-items: center;
230
+ gap: 8px;
231
+ margin-bottom: 8px;
232
+ }
233
+
234
+ .property-input {
235
+ flex: 1;
236
+ background: var(--bg-tertiary);
237
+ border: 1px solid var(--border);
238
+ color: var(--text-primary);
239
+ padding: 6px 10px;
240
+ border-radius: 4px;
241
+ font-size: 13px;
242
+ }
243
+
244
+ .property-input:focus {
245
+ outline: none;
246
+ border-color: var(--accent);
247
+ }
248
+
249
+ .property-select {
250
+ flex: 1;
251
+ background: var(--bg-tertiary);
252
+ border: 1px solid var(--border);
253
+ color: var(--text-primary);
254
+ padding: 6px 10px;
255
+ border-radius: 4px;
256
+ font-size: 13px;
257
+ cursor: pointer;
258
+ }
259
+
260
+ /* Layers Panel */
261
+ .layers-list {
262
+ display: flex;
263
+ flex-direction: column;
264
+ gap: 4px;
265
+ }
266
+
267
+ .layer-item {
268
+ display: flex;
269
+ align-items: center;
270
+ gap: 8px;
271
+ padding: 8px;
272
+ background: var(--bg-tertiary);
273
+ border-radius: 4px;
274
+ cursor: pointer;
275
+ transition: background 0.2s;
276
+ }
277
+
278
+ .layer-item:hover {
279
+ background: var(--bg-hover);
280
+ }
281
+
282
+ .layer-item.active {
283
+ background: var(--accent);
284
+ color: white;
285
+ }
286
+
287
+ .layer-visibility {
288
+ width: 16px;
289
+ height: 16px;
290
+ cursor: pointer;
291
+ }
292
+
293
+ .layer-name {
294
+ flex: 1;
295
+ font-size: 13px;
296
+ }
297
+
298
+ .layer-color {
299
+ width: 16px;
300
+ height: 16px;
301
+ border-radius: 2px;
302
+ border: 1px solid var(--border);
303
+ }
304
+
305
+ /* Status Bar */
306
+ .status-bar {
307
+ background: var(--bg-tertiary);
308
+ border-top: 1px solid var(--border);
309
+ padding: 4px 16px;
310
+ display: flex;
311
+ align-items: center;
312
+ justify-content: space-between;
313
+ font-size: 12px;
314
+ color: var(--text-secondary);
315
+ min-height: 28px;
316
+ }
317
+
318
+ .status-left {
319
+ display: flex;
320
+ gap: 20px;
321
+ }
322
+
323
+ .status-right {
324
+ display: flex;
325
+ gap: 20px;
326
+ }
327
+
328
+ .status-item {
329
+ display: flex;
330
+ align-items: center;
331
+ gap: 4px;
332
+ }
333
+
334
+ .status-label {
335
+ color: var(--text-secondary);
336
+ }
337
+
338
+ .status-value {
339
+ color: var(--text-primary);
340
+ font-weight: 500;
341
+ }
342
+
343
+ /* Context Menu */
344
+ .context-menu {
345
+ position: absolute;
346
+ background: var(--bg-tertiary);
347
+ border: 1px solid var(--border);
348
+ border-radius: 4px;
349
+ padding: 4px 0;
350
+ display: none;
351
+ z-index: 1000;
352
+ min-width: 150px;
353
+ box-shadow: 0 4px 12px rgba(0,0,0,0.3);
354
+ }
355
+
356
+ .context-menu-item {
357
+ padding: 6px 12px;
358
+ font-size: 13px;
359
+ cursor: pointer;
360
+ transition: background 0.2s;
361
+ }
362
+
363
+ .context-menu-item:hover {
364
+ background: var(--bg-hover);
365
+ }
366
+
367
+ /* Color Picker */
368
+ .color-picker {
369
+ display: flex;
370
+ gap: 4px;
371
+ flex-wrap: wrap;
372
+ }
373
+
374
+ .color-option {
375
+ width: 24px;
376
+ height: 24px;
377
+ border-radius: 4px;
378
+ cursor: pointer;
379
+ border: 2px solid transparent;
380
+ transition: all 0.2s;
381
+ }
382
+
383
+ .color-option:hover {
384
+ transform: scale(1.1);
385
+ }
386
+
387
+ .color-option.selected {
388
+ border-color: white;
389
+ box-shadow: 0 0 8px rgba(255,255,255,0.3);
390
+ }
391
+
392
+ /* Snap Indicator */
393
+ .snap-indicator {
394
+ position: absolute;
395
+ width: 8px;
396
+ height: 8px;
397
+ background: var(--snap-color);
398
+ border-radius: 50%;
399
+ pointer-events: none;
400
+ display: none;
401
+ z-index: 100;
402
+ transform: translate(-50%, -50%);
403
+ }
404
+
405
+ /* Dimension Text */
406
+ .dimension-text {
407
+ position: absolute;
408
+ background: var(--bg-primary);
409
+ padding: 2px 6px;
410
+ border-radius: 2px;
411
+ font-size: 11px;
412
+ color: var(--text-primary);
413
+ pointer-events: none;
414
+ white-space: nowrap;
415
+ border: 1px solid var(--border);
416
+ }
417
+
418
+ /* Buttons */
419
+ .btn {
420
+ padding: 6px 12px;
421
+ background: var(--accent);
422
+ color: white;
423
+ border: none;
424
+ border-radius: 4px;
425
+ cursor: pointer;
426
+ font-size: 13px;
427
+ transition: background 0.2s;
428
+ }
429
+
430
+ .btn:hover {
431
+ background: var(--accent-hover);
432
+ }
433
+
434
+ .btn-secondary {
435
+ background: var(--bg-tertiary);
436
+ color: var(--text-primary);
437
+ }
438
+
439
+ .btn-secondary:hover {
440
+ background: var(--bg-hover);
441
+ }
442
+
443
+ .btn-small {
444
+ padding: 4px 8px;
445
+ font-size: 12px;
446
+ }
447
+
448
+ /* Zoom Controls */
449
+ .zoom-controls {
450
+ position: absolute;
451
+ bottom: 20px;
452
+ right: 300px;
453
+ background: var(--bg-secondary);
454
+ border: 1px solid var(--border);
455
+ border-radius: 6px;
456
+ padding: 4px;
457
+ display: flex;
458
+ gap: 4px;
459
+ align-items: center;
460
+ }
461
+
462
+ .zoom-btn {
463
+ width: 28px;
464
+ height: 28px;
465
+ background: transparent;
466
+ color: var(--text-primary);
467
+ border: none;
468
+ border-radius: 4px;
469
+ cursor: pointer;
470
+ display: flex;
471
+ align-items: center;
472
+ justify-content: center;
473
+ transition: background 0.2s;
474
+ }
475
+
476
+ .zoom-btn:hover {
477
+ background: var(--bg-hover);
478
+ }
479
+
480
+ .zoom-level {
481
+ padding: 0 8px;
482
+ font-size: 12px;
483
+ color: var(--text-secondary);
484
+ min-width: 50px;
485
+ text-align: center;
486
+ }
487
+
488
+ /* Loading Overlay */
489
+ .loading-overlay {
490
+ position: fixed;
491
+ top: 0;
492
+ left: 0;
493
+ right: 0;
494
+ bottom: 0;
495
+ background: rgba(30, 30, 30, 0.9);
496
+ display: none;
497
+ align-items: center;
498
+ justify-content: center;
499
+ z-index: 2000;
500
+ }
501
+
502
+ .loading-spinner {
503
+ width: 48px;
504
+ height: 48px;
505
+ border: 4px solid var(--bg-tertiary);
506
+ border-top-color: var(--accent);
507
+ border-radius: 50%;
508
+ animation: spin 1s linear infinite;
509
+ }
510
+
511
+ @keyframes spin {
512
+ to { transform: rotate(360deg); }
513
+ }
514
+
515
+ /* Responsive */
516
+ @media (max-width: 768px) {
517
+ .properties-panel {
518
+ position: absolute;
519
+ right: -280px;
520
+ transition: right 0.3s;
521
+ z-index: 100;
522
+ }
523
+
524
+ .properties-panel.open {
525
+ right: 0;
526
+ }
527
+
528
+ .zoom-controls {
529
+ right: 20px;
530
+ }
531
+ }
532
+
533
+ /* Link styling */
534
+ .credit-link {
535
+ color: var(--accent);
536
+ text-decoration: none;
537
+ font-size: 12px;
538
+ }
539
+
540
+ .credit-link:hover {
541
+ text-decoration: underline;
542
+ }
543
+ </style>
544
+ </head>
545
+ <body>
546
+ <div class="app-container">
547
+ <!-- Header -->
548
+ <header class="header">
549
+ <div class="header-left">
550
+ <div class="logo">CivilCAD</div>
551
+ <nav class="header-nav">
552
+ <button class="nav-btn" onclick="newDrawing()">New</button>
553
+ <button class="nav-btn" onclick="saveDrawing()">Save</button>
554
+ <button class="nav-btn" onclick="loadDrawing()">Load</button>
555
+ <button class="nav-btn" onclick="exportImage()">Export</button>
556
+ </nav>
557
+ </div>
558
+ <div>
559
+ <a href="https://huggingface.co/spaces/akhaliq/anycoder" class="credit-link" target="_blank">Built with anycoder</a>
560
+ </div>
561
+ </header>
562
+
563
+ <!-- Main Content -->
564
+ <div class="main-content">
565
+ <!-- Toolbar -->
566
+ <aside class="toolbar">
567
+ <button class="tool-btn active" data-tool="pointer" onclick="selectTool('pointer')">
568
+
569
+ <span class="tool-tooltip">Select (S)</span>
570
+ </button>
571
+ <button class="tool-btn" data-tool="line" onclick="selectTool('line')">
572
+
573
+ <span class="tool-tooltip">Line (L)</span>
574
+ </button>
575
+ <button class="tool-btn" data-tool="rectangle" onclick="selectTool('rectangle')">
576
+
577
+ <span class="tool-tooltip">Rectangle (R)</span>
578
+ </button>
579
+ <button class="tool-btn" data-tool="circle" onclick="selectTool('circle')">
580
+
581
+ <span class="tool-tooltip">Circle (C)</span>
582
+ </button>
583
+ <button class="tool-btn" data-tool="arc" onclick="selectTool('arc')">
584
+
585
+ <span class="tool-tooltip">Arc (A)</span>
586
+ </button>
587
+ <button class="tool-btn" data-tool="polyline" onclick="selectTool('polyline')">
588
+
589
+ <span class="tool-tooltip">Polyline (P)</span>
590
+ </button>
591
+ <button class="tool-btn" data-tool="dimension" onclick="selectTool('dimension')">
592
+ 📏
593
+ <span class="tool-tooltip">Dimension (D)</span>
594
+ </button>
595
+ <button class="tool-btn" data-tool="text" onclick="selectTool('text')">
596
+ T
597
+ <span class="tool-tooltip">Text (T)</span>
598
+ </button>
599
+ <div class="tool-separator"></div>
600
+ <button class="tool-btn" data-tool="pan" onclick="selectTool('pan')">
601
+
602
+ <span class="tool-tooltip">Pan (H)</span>
603
+ </button>
604
+ <button class="tool-btn" data-tool="zoom" onclick="selectTool('zoom')">
605
+ 🔍
606
+ <span class="tool-tooltip">Zoom Window (Z)</span>
607
+ </button>
608
+ <div class="tool-separator"></div>
609
+ <button class="tool-btn" onclick="undo()">
610
+
611
+ <span class="tool-tooltip">Undo (Ctrl+Z)</span>
612
+ </button>
613
+ <button class="tool-btn" onclick="redo()">
614
+
615
+ <span class="tool-tooltip">Redo (Ctrl+Y)</span>
616
+ </button>
617
+ <button class="tool-btn" onclick="deleteSelected()">
618
+ 🗑
619
+ <span class="tool-tooltip">Delete (Del)</span>
620
+ </button>
621
+ </aside>
622
+
623
+ <!-- Canvas Container -->
624
+ <main class="canvas-container" id="canvasContainer">
625
+ <canvas id="drawingCanvas"></canvas>
626
+ <canvas class="canvas-grid" id="gridCanvas"></canvas>
627
+ <div class="snap-indicator" id="snapIndicator"></div>
628
+
629
+ <!-- Zoom Controls -->
630
+ <div class="zoom-controls">
631
+ <button class="zoom-btn" onclick="zoomOut()">−</button>
632
+ <span class="zoom-level" id="zoomLevel">100%</span>
633
+ <button class="zoom-btn" onclick="zoomIn()">+</button>
634
+ <button class="zoom-btn" onclick="fitToScreen()">⊡</button>
635
+ </div>
636
+ </main>
637
+
638
+ <!-- Properties Panel -->
639
+ <aside class="properties-panel">
640
+ <div class="panel-header">
641
+ Properties
642
+ <button class="btn btn-small btn-secondary" onclick="togglePanel()">Hide</button>
643
+ </div>
644
+ <div class="panel-content">
645
+ <!-- Drawing Properties -->
646
+ <div class="property-group">
647
+ <div class="property-label">Drawing</div>
648
+ <div class="property-row">
649
+ <label style="font-size: 12px;">Units:</label>
650
+ <select class="property-select" id="units" onchange="updateUnits()">
651
+ <option value="mm">Millimeters</option>
652
+ <option value="cm">Centimeters</option>
653
+ <option value="m" selected>Meters</option>
654
+ <option value="ft">Feet</option>
655
+ <option value="in">Inches</option>
656
+ </select>
657
+ </div>
658
+ <div class="property-row">
659
+ <label style="font-size: 12px;">Grid:</label>
660
+ <input type="checkbox" id="gridToggle" checked onchange="toggleGrid()">
661
+ <label style="font-size: 12px;">Snap:</label>
662
+ <input type="checkbox" id="snapToggle" checked onchange="toggleSnap()">
663
+ </div>
664
+ <div class="property-row">
665
+ <label style="font-size: 12px;">Grid Size:</label>
666
+ <input type="number" class="property-input" id="gridSize" value="10" min="1" max="100" onchange="updateGridSize()">
667
+ </div>
668
+ </div>
669
+
670
+ <!-- Line Properties -->
671
+ <div class="property-group">
672
+ <div class="property-label">Line</div>
673
+ <div class="property-row">
674
+ <label style="font-size: 12px;">Color:</label>
675
+ <div class="color-picker" id="lineColorPicker">
676
+ <div class="color-option selected" style="background: #ffffff" data-color="#ffffff"></div>
677
+ <div class="color-option" style="background: #ff0000" data-color="#ff0000"></div>
678
+ <div class="color-option" style="background: #00ff00" data-color="#00ff00"></div>
679
+ <div class="color-option" style="background: #0000ff" data-color="#0000ff"></div>
680
+ <div class="color-option" style="background: #ffff00" data-color="#ffff00"></div>
681
+ <div class="color-option" style="background: #ff00ff" data-color="#ff00ff"></div>
682
+ <div class="color-option" style="background: #00ffff" data-color="#00ffff"></div>
683
+ <div class="color-option" style="background: #ff8800" data-color="#ff8800"></div>
684
+ </div>
685
+ </div>
686
+ <div class="property-row">
687
+ <label style="font-size: 12px;">Width:</label>
688
+ <input type="number" class="property-input" id="lineWidth" value="1" min="0.1" max="10" step="0.1">
689
+ </div>
690
+ <div class="property-row">
691
+ <label style="font-size: 12px;">Style:</label>
692
+ <select class="property-select" id="lineStyle">
693
+ <option value="solid">Solid</option>
694
+ <option value="dashed">Dashed</option>
695
+ <option value="dotted">Dotted</option>
696
+ <option value="center">Center Line</option>
697
+ </select>
698
+ </div>
699
+ </div>
700
+
701
+ <!-- Layers -->
702
+ <div class="property-group">
703
+ <div class="property-label">Layers</div>
704
+ <div class="layers-list" id="layersList">
705
+ <div class="layer-item active" data-layer="0">
706
+ <input type="checkbox" class="layer-visibility" checked>
707
+ <span class="layer-name">Layer 1</span>
708
+ <div class="layer-color" style="background: #ffffff"></div>
709
+ </div>
710
+ </div>
711
+ <div style="margin-top: 8px; display: flex; gap: 4px;">
712
+ <button class="btn btn-small" onclick="addLayer()">Add</button>
713
+ <button class="btn btn-small btn-secondary" onclick="deleteLayer()">Delete</button>
714
+ </div>
715
+ </div>
716
+
717
+ <!-- Object Info -->
718
+ <div class="property-group">
719
+ <div class="property-label">Selected Object</div>
720
+ <div id="objectInfo">
721
+ <div style="font-size: 12px; color: var(--text-secondary);">No object selected</div>
722
+ </div>
723
+ </div>
724
+ </div>
725
+ </aside>
726
+ </div>
727
+
728
+ <!-- Status Bar -->
729
+ <footer class="status-bar">
730
+ <div class="status-left">
731
+ <div class="status-item">
732
+ <span class="status-label">X:</span>
733
+ <span class="status-value" id="mouseX">0.00</span>
734
+ </div>
735
+ <div class="status-item">
736
+ <span class="status-label">Y:</span>
737
+ <span class="status-value" id="mouseY">0.00</span>
738
+ </div>
739
+ <div class="status-item">
740
+ <span class="status-label">Tool:</span>
741
+ <span class="status-value" id="currentTool">Select</span>
742
+ </div>
743
+ </div>
744
+ <div class="status-right">
745
+ <div class="status-item">
746
+ <span class="status-label">Objects:</span>
747
+ <span class="status-value" id="objectCount">0</span>
748
+ </div>
749
+ <div class="status-item">
750
+ <span class="status-label">Layer:</span>
751
+ <span class="status-value" id="currentLayer">Layer 1</span>
752
+ </div>
753
+ <div class="status-item">
754
+ <span class="status-label">Snap:</span>
755
+ <span class="status-value" id="snapStatus">ON</span>
756
+ </div>
757
+ </div>
758
+ </footer>
759
+ </div>
760
+
761
+ <!-- Context Menu -->
762
+ <div class="context-menu" id="contextMenu">
763
+ <div class="context-menu-item" onclick="copyObject()">Copy</div>
764
+ <div class="context-menu-item" onclick="pasteObject()">Paste</div>
765
+ <div class="context-menu-item" onclick="deleteSelected()">Delete</div>
766
+ <div class="context-menu-item" onclick="bringToFront()">Bring to Front</div>
767
+ <div class="context-menu-item" onclick="sendToBack()">Send to Back</div>
768
+ </div>
769
+
770
+ <!-- Loading Overlay -->
771
+ <div class="loading-overlay" id="loadingOverlay">
772
+ <div class="loading-spinner"></div>
773
+ </div>
774
+
775
+ <script>
776
+ // Global Variables
777
+ const canvas = document.getElementById('drawingCanvas');
778
+ const ctx = canvas.getContext('2d');
779
+ const gridCanvas = document.getElementById('gridCanvas');
780
+ const gridCtx = gridCanvas.getContext('2d');
781
+
782
+ let currentTool = 'pointer';
783
+ let isDrawing = false;
784
+ let startX, startY;
785
+ let objects = [];
786
+ let selectedObject = null;
787
+ let currentLayer = 0;
788
+ let layers = [{ name: 'Layer 1', visible: true, color: '#ffffff' }];
789
+ let zoom = 1;
790
+ let panX = 0, panY = 0;
791
+ let isPanning = false;
792
+ let lastPanX, lastPanY;
793
+ let gridSize = 10;
794
+ let snapEnabled = true;
795
+ let gridEnabled = true;
796
+ let units = 'm';
797
+ let history = [];
798
+ let historyStep = -1;
799
+ let clipboard = null;
800
+ let tempPoints = [];
801
+ let lineColor = '#ffffff';
802
+ let lineWidth = 1;
803
+ let lineStyle = 'solid';
804
+
805
+ // Initialize
806
+ function init() {
807
+ resizeCanvas();
808
+ drawGrid();
809
+ setupEventListeners();
810
+ setupColorPicker();
811
+ window.addEventListener('resize', resizeCanvas);
812
+ }
813
+
814
+ // Resize Canvas
815
+ function resizeCanvas() {
816
+ const container = document.getElementById('canvasContainer');
817
+ canvas.width = container.clientWidth;
818
+ canvas.height = container.clientHeight;
819
+ gridCanvas.width = container.clientWidth;
820
+ gridCanvas.height = container.clientHeight;
821
+ redraw();
822
+ drawGrid();
823
+ }
824
+
825
+ // Setup Event Listeners
826
+ function setupEventListeners() {
827
+ canvas.addEventListener('mousedown', handleMouseDown);
828
+ canvas.addEventListener('mousemove', handleMouseMove);
829
+ canvas.addEventListener('mouseup', handleMouseUp);
830
+ canvas.addEventListener('wheel', handleWheel);
831
+ canvas.addEventListener('contextmenu', handleContextMenu);
832
+ document.addEventListener('keydown', handleKeyDown);
833
+ document.addEventListener('keyup', handleKeyUp);
834
+ }
835
+
836
+ // Mouse Events
837
+ function handleMouseDown(e) {
838
+ const rect = canvas.getBoundingClientRect();
839
+ const x = (e.clientX - rect.left - panX) / zoom;
840
+ const y = (e.clientY - rect.top - panY) / zoom;
841
+
842
+ if (snapEnabled) {
843
+ const snapped = snapToGrid(x, y);
844
+ startX = snapped.x;
845
+ startY = snapped.y;
846
+ } else {
847
+ startX = x;
848
+ startY = y;
849
+ }
850
+
851
+ if (currentTool === 'pointer') {
852
+ selectObjectAt(x, y);
853
+ } else if (currentTool === 'pan') {
854
+ isPanning = true;
855
+ lastPanX = e.clientX;
856
+ lastPanY = e.clientY;
857
+ canvas.style.cursor = 'grabbing';
858
+ } else if (currentTool === 'polyline') {
859
+ tempPoints.push({ x: startX, y: startY });
860
+ if (tempPoints.length > 1) {
861
+ drawPolylinePreview();
862
+ }
863
+ } else if (currentTool === 'text') {
864
+ const text = prompt('Enter text:');
865
+ if (text) {
866
+ addObject({
867
+ type: 'text',
868
+ x: startX,
869
+ y: startY,
870
+ text: text,
871
+ color: lineColor,
872
+ layer: currentLayer
873
+ });
874
+ }
875
+ } else {
876
+ isDrawing = true;
877
+ }
878
+ }
879
+
880
+ function handleMouseMove(e) {
881
+ const rect = canvas.getBoundingClientRect();
882
+ const x = (e.clientX - rect.left - panX) / zoom;
883
+ const y = (e.clientY - rect.top - panY) / zoom;
884
+
885
+ updateMousePosition(x, y);
886
+
887
+ if (snapEnabled && currentTool !== 'pan') {
888
+ const snapped = snapToGrid(x, y);
889
+ showSnapIndicator(snapped.x, snapped.y);
890
+ } else {
891
+ hideSnapIndicator();
892
+ }
893
+
894
+ if (isPanning) {
895
+ panX += e.clientX - lastPanX;
896
+ panY += e.clientY - lastPanY;
897
+ lastPanX = e.clientX;
898
+ lastPanY = e.clientY;
899
+ redraw();
900
+ drawGrid();
901
+ } else if (isDrawing) {
902
+ redraw();
903
+ drawPreview(x, y);
904
+ } else if (currentTool === 'polyline' && tempPoints.length > 0) {
905
+ redraw();
906
+ drawPolylinePreview(x, y);
907
+ }
908
+ }
909
+
910
+ function handleMouseUp(e) {
911
+ if (isPanning) {
912
+ isPanning = false;
913
+ canvas.style.cursor = 'grab';
914
+ return;
915
+ }
916
+
917
+ if (!isDrawing) return;
918
+
919
+ const rect = canvas.getBoundingClientRect();
920
+ const x = (e.clientX - rect.left - panX) / zoom;
921
+ const y = (e.clientY - rect.top - panY) / zoom;
922
+
923
+ let endX = x, endY = y;
924
+ if (snapEnabled) {
925
+ const snapped = snapToGrid(x, y);
926
+ endX = snapped.x;
927
+ endY = snapped.y;
928
+ }
929
+
930
+ if (currentTool === 'line') {
931
+ addObject({
932
+ type: 'line',
933
+ x1: startX,
934
+ y1: startY,
935
+ x2: endX,
936
+ y2: endY,
937
+ color: lineColor,
938
+ width: lineWidth,
939
+ style: lineStyle,
940
+ layer: currentLayer
941
+ });
942
+ } else if (currentTool === 'rectangle') {
943
+ addObject({
944
+ type: 'rectangle',
945
+ x: Math.min(startX, endX),
946
+ y: Math.min(startY, endY),
947
+ width: Math.abs(endX - startX),
948
+ height: Math.abs(endY - startY),
949
+ color: lineColor,
950
+ lineWidth: lineWidth,
951
+ style: lineStyle,
952
+ layer: currentLayer
953
+ });
954
+ } else if (currentTool === 'circle') {
955
+ const radius = Math.sqrt(Math.pow(endX - startX, 2) + Math.pow(endY - startY, 2));
956
+ addObject({
957
+ type: 'circle',
958
+ x: startX,
959
+ y: startY,
960
+ radius: radius,
961
+ color: lineColor,
962
+ lineWidth: lineWidth,
963
+ style: lineStyle,
964
+ layer: currentLayer
965
+ });
966
+ } else if (currentTool === 'arc') {
967
+ const radius = Math.sqrt(Math.pow(endX - startX, 2) + Math.pow(endY - startY, 2));
968
+ const angle = Math.atan2(endY - startY, endX - startX);
969
+ addObject({
970
+ type: 'arc',
971
+ x: startX,
972
+ y: startY,
973
+ radius: radius,
974
+ startAngle: 0,
975
+ endAngle: angle,
976
+ color: lineColor,
977
+ lineWidth: lineWidth,
978
+ style: lineStyle,
979
+ layer: currentLayer
980
+ });
981
+ } else if (currentTool === 'dimension') {
982
+ const distance = Math.sqrt(Math.pow(endX - startX, 2) + Math.pow(endY - startY, 2));
983
+ const midX = (startX + endX) / 2;
984
+ const midY = (startY + endY) / 2;
985
+ addObject({
986
+ type: 'dimension',
987
+ x1: startX,
988
+ y1: startY,
989
+ x2: endX,
990
+ y2: endY,
991
+ text: formatDistance(distance),
992
+ color: lineColor,
993
+ layer: currentLayer
994
+ });
995
+ } else if (currentTool === 'zoom') {
996
+ const zoomRect = {
997
+ x: Math.min(startX, endX),
998
+ y: Math.min(startY, endY),
999
+ width: Math.abs(endX - startX),
1000
+ height: Math.abs(endY - startY)
1001
+ };
1002
+ zoomToRect(zoomRect);
1003
+ }
1004
+
1005
+ isDrawing = false;
1006
+ redraw();
1007
+ }
1008
+
1009
+ function handleWheel(e) {
1010
+ e.preventDefault();
1011
+ const delta = e.deltaY > 0 ? 0.9 : 1.1;
1012
+ const newZoom = Math.max(0.1, Math.min(10, zoom * delta));
1013
+
1014
+ const rect = canvas.getBoundingClientRect();
1015
+ const mouseX = e.clientX - rect.left;
1016
+ const mouseY = e.clientY - rect.top;
1017
+
1018
+ panX = mouseX - (mouseX - panX) * (newZoom / zoom);
1019
+ panY = mouseY - (mouseY - panY) * (newZoom / zoom);
1020
+
1021
+ zoom = newZoom;
1022
+ updateZoomDisplay();
1023
+ redraw();
1024
+ drawGrid();
1025
+ }
1026
+
1027
+ function handleContextMenu(e) {
1028
+ e.preventDefault();
1029
+ const contextMenu = document.getElementById('contextMenu');
1030
+ contextMenu.style.display = 'block';
1031
+ contextMenu.style.left = e.clientX + 'px';
1032
+ contextMenu.style.top = e.clientY + 'px';
1033
+ }
1034
+
1035
+ function handleKeyDown(e) {
1036
+ // Keyboard shortcuts
1037
+ if (e.ctrlKey || e.metaKey) {
1038
+ switch(e.key.toLowerCase()) {
1039
+ case 'z':
1040
+ e.preventDefault();
1041
+ undo();
1042
+ break;
1043
+ case 'y':
1044
+ e.preventDefault();
1045
+ redo();
1046
+ break;
1047
+ case 's':
1048
+ e.preventDefault();
1049
+ saveDrawing();
1050
+ break;
1051
+ case 'o':
1052
+ e.preventDefault();
1053
+ loadDrawing();
1054
+ break;
1055
+ case 'c':
1056
+ e.preventDefault();
1057
+ copyObject();
1058
+ break;
1059
+ case 'v':
1060
+ e.preventDefault();
1061
+ pasteObject();
1062
+ break;
1063
+ }
1064
+ } else {
1065
+ switch(e.key.toLowerCase()) {
1066
+ case 'delete':
1067
+ case 'backspace':
1068
+ deleteSelected();
1069
+ break;
1070
+ case 's':
1071
+ selectTool('pointer');
1072
+ break;
1073
+ case 'l':
1074
+ selectTool('line');
1075
+ break;
1076
+ case 'r':
1077
+ selectTool('rectangle');
1078
+ break;
1079
+ case 'c':
1080
+ selectTool('circle');
1081
+ break;
1082
+ case 'a':
1083
+ selectTool('arc');
1084
+ break;
1085
+ case 'p':
1086
+ selectTool('polyline');
1087
+ break;
1088
+ case 'd':
1089
+ selectTool('dimension');
1090
+ break;
1091
+ case 't':
1092
+ selectTool('text');
1093
+ break;
1094
+ case 'h':
1095
+ selectTool('pan');
1096
+ break;
1097
+ case 'z':
1098
+ selectTool('zoom');
1099
+ break;
1100
+ case 'escape':
1101
+ if (currentTool === 'polyline') {
1102
+ if (tempPoints.length > 1) {
1103
+ addObject({
1104
+ type: 'polyline',
1105
+ points: [...tempPoints],
1106
+ color: lineColor,
1107
+ width: lineWidth,
1108
+ style: lineStyle,
1109
+ layer: currentLayer
1110
+ });
1111
+ }
1112
+ tempPoints = [];
1113
+ redraw();
1114
+ }
1115
+ break;
1116
+ }
1117
+ }
1118
+ }
1119
+
1120
+ function handleKeyUp(e) {
1121
+ document.addEventListener('click', () => {
1122
+ document.getElementById('contextMenu').style.display = 'none';
1123
+ }, { once: true });
1124
+ }
1125
+
1126
+ // Tool Selection
1127
+ function selectTool(tool) {
1128
+ currentTool = tool;
1129
+ document.querySelectorAll('.tool-btn').forEach(btn => {
1130
+ btn.classList.remove('active');
1131
+ });
1132
+ document.querySelector(`[data-tool="${tool}"]`).classList.add('active');
1133
+
1134
+ document.getElementById('currentTool').textContent =
1135
+ tool.charAt(0).toUpperCase() + tool.slice(1);
1136
+
1137
+ // Update cursor
1138
+ if (tool === 'pan') {
1139
+ canvas.style.cursor = 'grab';
1140
+ } else if (tool === 'zoom') {
1141
+ canvas.style.cursor = 'zoom-in';
1142
+ } else if (tool === 'text') {
1143
+ canvas.style.cursor = 'text';
1144
+ } else {
1145
+ canvas.style.cursor = 'crosshair';
1146
+ }
1147
+
1148
+ // Clear polyline if switching tools
1149
+ if (tool !== 'polyline' && tempPoints.length > 0) {
1150
+ if (tempPoints.length > 1) {
1151
+ addObject({
1152
+ type: 'polyline',
1153
+ points: [...tempPoints],
1154
+ color: lineColor,
1155
+ width: lineWidth,
1156
+ style: lineStyle,
1157
+ layer: currentLayer
1158
+ });
1159
+ }
1160
+ tempPoints = [];
1161
+ redraw();
1162
+ }
1163
+ }
1164
+
1165
+ // Drawing Functions
1166
+ function drawGrid() {