-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
723 lines (676 loc) · 21.6 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<title>Title</title>
<style>
.draggable, .main, .group {
/* 禁止觸摸屏事件 */
touch-action: none;
user-select: none;
}
.text-center {
text-align: center;
}
.green {
color: #0b8235;
}
.white {
color: #fff;
}
.gray {
color: #635f63;
}
.setting-wrapper {
width: 100%;
margin: 0 auto;
}
.setting-wrapper > div {
margin-bottom: 10px;
}
.modal, .add-device-modal {
display: none;
position: fixed;
background-color: rgba(134, 130, 130, 0.8);
width: 100%;
height: 100%;
top: 0;
left: 0;
z-index: 1;
}
.modal .container {
text-align: center;
}
.add-device-modal .add-device-form {
position: absolute;
background-color: #fff;
left: 50%;
top: 50%;
width: 240px;
height: 160px;
padding: 10px 50px;
margin-left: -120px;
margin-top: -80px;
}
.add-device-modal .add-device-form > div {
margin-top: 10px;
}
.add-device-modal .add-device-form .close {
position: absolute;
top: 0;
right: 0;
padding: 5px;
margin-top: 10px;
margin-right: 10px;
}
.body {
display: flex;
flex-wrap: nowrap;
align-items: flex-start;
z-index: 1;
margin-bottom: 100px;
}
.body .operator-wrapper {
flex-basis: 200px;
padding: 10px;
border: 1px solid #ccc;
}
.body .operator-wrapper .title {
position: relative;
height: 30px;
}
.body .operator-wrapper .title .operator-add {
position: absolute;
top: 0;
right: 0;
}
.body .operator-wrapper .container {
min-height: 300px;
max-height: 500px;
overflow-y: auto;
}
.body .operator-wrapper .container .device-list-wrapper {
display: flex;
flex-wrap: wrap;
width: 200px;
}
.body .device-wrapper {
background-color: #cccccc;
margin-top: 5px;
padding: 5px;
}
.body .device-wrapper.draggable {
background-color: #12cc4b;
cursor: move;
}
/* 如果可以拖動,隱藏 div 中的顯示按鈕位置 */
.body .operator-wrapper .device-list-wrapper .draggable .show-location {
display: none;
}
.body .main-wrapper {
border: 1px solid #ccc;
margin: 10px;
position: relative;
}
.body .main-wrapper .background-image-div {
background-image: url("./images/6aedf07074a3183023e855c5729757eb--open-kitchen-restaurant-restaurant-layout.jpg");
background-repeat: no-repeat;
background-size: 100% 100%;
z-index: -1;
position: absolute;
top: 0;
left: 0;
}
.body .main-wrapper .main {
background-color: rgba(255, 255, 255, 0.8);
border: 1px red solid;
position: relative;
}
/* 擺放區的統計顯示 */
.body .main-wrapper .main .group {
position: absolute;
top: 0;
left: 0;
display: inline-block;
padding: 2px;
height: 15px;
width: 15px;
font-size: 12px;
line-height: 25px;
text-align: right;
color: red;
background-image: url("./images/Map_Marker_Ball_Pink_32px_1061216_easyicon.net.png");
background-repeat: no-repeat;
background-size: 100% 100%;
}
.body .main-wrapper .main .group.highlight {
background-color: yellow;
}
.body .main-wrapper .main .group p {
background-color: red;
color: white;
width: 80px;
text-align: left;
padding: 5px;
}
.body .main-wrapper .main .group.can-drop {
color: #000;
background-color: #4e4;
}
.body .main-wrapper .main .group.drop-target {
background-color: #29e;
border-color: #fff;
border-style: solid;
}
.body .main .main-device-list-modal {
background-color: #fff;
border: 1px solid #cccccc;
width: 200px;
padding: 10px;
}
</style>
</head>
<body>
<div id="QRModal" class="modal">
<div class="container">
<div>
<button type="button" class="narrow">縮小</button>
<button type="button" class="enlarge">放大</button>
<button type="button" class="close">關閉</button>
</div>
<img id="qrcode" width="256" src="./images/erCode.png">
</div>
</div>
<div id="addDeviceModal" class="add-device-modal">
<div class="add-device-form">
<div class="close">
<button type="button" id="closeAddDeviceBtn">X</button>
</div>
<div class="text-center">新增設備</div>
<div>設備名稱:<input type="text" id="deviceName" maxlength="50"></div>
<div>
選擇設備類型:
<select id="deviceTypeSelect"></select>
</div>
<div>
選擇設備位置:
<select id="devicePositionSelect"></select>
</div>
<div class="text-center">
<button type="button" id="AddDeviceBtn">新增</button>
</div>
</div>
</div>
<div id="settingWrapper" class="setting-wrapper">
<div>
<div class="title">設置面積</div>
<div>長:<input type="number" name="roomLength" id="roomLength" value="500"></div>
<div>寬:<input type="number" name="roomWidth" id="roomWidth" value="800"></div>
<button type="button" id="changeArea">改變面積大小</button>
</div>
<div>
設置背景圖片
<input type="file" name="backgroundImage" id="backgroundImage" accept="image/*" />
</div>
<div>調整背景圖片不透明度:<input type="range" name="opacity" id="opacity" min="0" max="1" step="0.1" value="0.8"></div>
<div id="areaScale" class="area-scale" data-scale="1">
<span>畫布設置:</span>
<button type="button" class="reset">恢復畫布默認比例</button>
<button type="button" class="narrow">縮小</button>
<button type="button" class="enlarge">放大</button>
<span class="text">1:<span class="num">1</span></span>
</div>
<div>
<button type="button" id="serialize">序列化</button>
</div>
</div>
<div class="body">
<div class="operator-wrapper">
<div class="title">
<div class="text-center">
設備列表
</div>
<div class="operator-add">
<button id="showAddDeviceBtn" type="button">新增</button>
</div>
</div>
<div class="container">
<div id="deviceListWrapper" class="device-list-wrapper">
</div>
</div>
</div>
<div id="mainWrapper" class="main-wrapper">
<div class="main" id="main"></div>
<div class="background-image-div"></div>
</div>
</div>
<div class="tips">
<div>使用說明:
<p>1. 輸出長寬後,點擊改變面積按鈕,可以改變紅框的大小</p>
<p>2. 可以上傳背景圖片</p>
<p>3. 可以設置背景圖片的透明度</p>
<p>4. 點擊設備列表中的新增按鈕,可以新增設備.</p>
<p>5. 可以從設備列表拖動到紅框中</p>
<p>6. 紅框中的數字,代表在對應位置有多少台設備</p>
<p>7. 雙擊紅框中的設備數字,可以展開對應位置的設備列表</p>
<p>7.1 點擊隱藏,會將設備列表詳情全部隱藏.</p>
<p>7.2 點擊位置設備列表詳情中的刪除按鈕,會將對應設備移除.(移除後可以重新從左邊的列表拖進紅框)</p>
<p>8. 坐標的設備列表,點擊刪除後,會將對應設備刪除,並且已擺放的位置也會清空</p>
</div>
</div>
<script type="text/javascript" src="./js/jquery-1.12.4.min.js"></script>
<script src="./js/interact.min.js"></script>
<script src="./js/draggable.js?v=0.0.5"></script>
<script>
// 初始化設備列表.如果需要頁面加載後顯示,則設置該對象的值
var initDeviceData = [
{
// 如果是初始化數據,比如從後端請求的歷史數據,ID 建議設置為負數,以免和新增設備時自動生成的 ID 重復
id: -1,
name: '張淞\'s 小米米家智能攝像頭',
type: 'camera',
devicePosition: 'ceiling',
groupId: -1,
},
{
// 如果是初始化數據,比如從後端請求的歷史數據,ID 建議設置為負數,以免和新增設備時自動生成的 ID 重復
id: -2,
name: '22張淞\'s 小米米家智能攝像頭',
type: 'camera',
devicePosition: 'ceiling',
groupId: -1,
},
{
// 如果是初始化數據,比如從後端請求的歷史數據,ID 建議設置為負數,以免和新增設備時自動生成的 ID 重復
id: -3,
name: '33張淞\'s 小米米家智能攝像頭',
type: 'camera',
devicePosition: 'ceiling',
},
{
// 如果是初始化數據,比如從後端請求的歷史數據,ID 建議設置為負數,以免和新增設備時自動生成的 ID 重復
id: -4,
name: '444\'s 小米米家智能攝像頭',
type: 'camera',
devicePosition: 'ceiling',
},
{
// 如果是初始化數據,比如從後端請求的歷史數據,ID 建議設置為負數,以免和新增設備時自動生成的 ID 重復
id: -5,
name: '555\'s 小米米家智能攝像頭',
type: 'camera',
devicePosition: 'ceiling',
},
];
var initGroupData = [
{
id: -1,
x: 111,
y: 111,
total: 2,
},
];
// 使用自增 ID 作為每個新增設備的唯一標識
var deviceSerialNumber = 1;
var groupSerialNumber = 1;
// 新增設備時的下拉框選項
var deviceTypeMap = {
monitor: '顯示器',
camera: '攝像頭',
sound: '音響',
};
// 設備位置
var devicePositionMap = {
floor: '地上',
wall: '牆上',
ceiling: '天花板上',
};
// 當創建一個對象時,最外層 div 的 ID 生成規則
var deviceWrapperIdTemplate = 'device-@ID';
// dom 對象
var backgroundImageDivDom = $('.background-image-div');
var addDeviceModalDom = $('#addDeviceModal');
var deviceListWrapperDom = $('#deviceListWrapper');
var mainDom = $('#main');
var areaScaleDom = $('#areaScale');
// 設備對象.
var devices = {};
// 將初始化數據列表轉換為 object,ID 為 key
for (var index in initDeviceData) {
var item = initDeviceData[index];
devices[item.id] = item;
}
// 改變面積
function changeArea() {
var height = $('#roomLength').val();
var width = $('#roomWidth').val();
if (isNaN(height) || height < 300) {
alert('面積長必須大於300');
return;
}
if (isNaN(width) || width < 300) {
alert('面積寬必須大於300');
return;
}
mainDom.width(width + 'px').height(height + 'px');
mainDom.attr('data-width', width);
mainDom.attr('data-height', height);
backgroundImageDivDom.width(width + 'px').height(height + 'px');
}
/**
* 改變畫布比例
* @param next 改變後的畫布比例
*/
function changeAreaScale(next) {
// 先隱藏全部設備詳情
hiddenMainDeviceListModal();
// 獲取當前比例
var prevScale = Number(areaScaleDom.attr('data-scale'));
var scale = Math.floor(next / prevScale * 100) / 100;
var areaWidth = (mainDom.width() * scale).toFixed(2);
var areaHeight = (mainDom.height() * scale).toFixed(2);
// 更新面積div 寬高, 只保留兩位小數
mainDom.width(areaWidth + 'px').height(areaHeight + 'px');
backgroundImageDivDom.width(areaWidth + 'px').height(areaHeight + 'px');
// 更新分組坐標
mainDom.children('.group').each(function (index, item) {
// 當畫布比例改變時,以子div的中心更新位置
var domByJq = $(this);
var originWidth = domByJq.width();
var originHeight = domByJq.height();
var x = Number(domByJq.attr('data-x')) + originWidth / 2;
var y = Number(domByJq.attr('data-y')) + originHeight / 2;
x = x * scale - originWidth / 2;
y = y * scale - originHeight / 2;
moveDomByCss(this, x, y);
});
areaScaleDom.attr('data-scale', next);
areaScaleDom.find('.num').html(next);
}
// 清除新增設備表單並關閉模態窗
function closeAddDeviceModal() {
$('#deviceName').val('');
$('#deviceTypeSelect').val('');
$('#devicePositionSelect').val('');
addDeviceModalDom.hide();
}
// 同步 devices 數組中的值到頁面的設備列表
function syncDevices() {
for (var key in devices) {
var item = devices[key];
if (!item.dom) {
// 如果對象中不存在 dom 對象,則創建 dom 對象並顯示在頁面中
var dom = $(
'<div class="device-wrapper ' + (item.groupId ? '' : 'draggable') + '" id="' +
deviceWrapperIdTemplate.replace('@ID', key) + '" data-id="' +
key + '">' +
'<div class="device-name"><span class="gray">設備名稱:</span><span>' + item.name + '</span></div>' +
'<div class="device-type"><span class="gray">設備類型:</span><span class="">' + deviceTypeMap[item.type] +
'</span></div>' +
'<div class="device-position"><span class="gray">設備位置:</span><span class="">' +
devicePositionMap[item.devicePosition] +
'</span></div>' +
'<div><button type="button" class="show-location">查看坐標</button><button type="button" class="show-qr-code">查看二維碼</button><button type="button" class="delete">刪除</button></div>' +
'</div>');
deviceListWrapperDom.append(dom);
item.dom = dom[0];
} else {
// 檢查是否存在 groupId,如果存在,移除 draggable class
if (item.groupId) {
item.dom.classList.remove('draggable');
} else {
item.dom.classList.add('draggable');
}
}
}
}
function syncGroups(arr) {
for (var i = 0; i < arr.length; i++) {
var obj = arr[i];
var dom = document.querySelector('#main div[data-group-id="' + obj.id + '"]');
if (!dom) {
var drag = $('<div class="flag group" data-group-id="' + obj.id + '">' + obj.total + '</div>')[0];
mainDom.append(drag);
moveDomByCss(drag, obj.x, obj.y);
}
}
}
$(function () {
// 序列化,獲取全部信息
$('#serialize').on('click', function () {
hiddenMainDeviceListModal();
// 獲取寬高
var width = mainDom.attr('data-width');
var height = mainDom.attr('data-height');
// 畫面比例
var scale = areaScaleDom.attr('data-scale');
// 透明度
var opacity = $('#opacity').val();
// 背景圖片(未處理)
var backgroundImage = $('#backgroundImage').val();
// 設備列表
var deviceList = [];
var list = $('#deviceListWrapper .device-wrapper');
for (var i = 0; i < list.length; i++) {
var id = list[i].getAttribute('data-id');
deviceList.push({
id: devices[id].id,
name: devices[id].name,
type: devices[id].type,
devicePosition: devices[id].devicePosition,
groupId: devices[id].groupId,
});
}
var groupList = [];
// 獲取分組信息
list = mainDom.children('.group');
for (var i = 0; i < list.length; i++) {
var id = list[i].getAttribute('data-group-id');
groupList.push({
id: id,
// 注意,該值可能為小數,如果要保存數據庫,需要處理位數
x: list[i].getAttribute('data-x'),
// 注意,該值可能為小數,如果要保存數據庫,需要處理位數
y: list[i].getAttribute('data-y'),
total: list[i].innerText,
});
}
console.log('序列化信息', {
width: width,
height: height,
scale: scale,
opacity: opacity,
backgroundImage: backgroundImage,
deviceList: deviceList,
groupList: groupList,
});
alert('請打開控制台查看內容');
});
// 初始化面積 div
changeArea();
// 初始化設備下拉框
var deviceTypeHtml = '';
for (var item in deviceTypeMap) {
deviceTypeHtml += '<option value="' + item + '">' + deviceTypeMap[item] + '</option>';
}
$('#deviceTypeSelect').html(deviceTypeHtml);
// 初始化設備位置
var devicePositionHtml = '';
for (var item in devicePositionMap) {
devicePositionHtml += '<option value="' + item + '">' + devicePositionMap[item] + '</option>';
}
$('#devicePositionSelect').html(devicePositionHtml);
// 初始化設備數據
syncDevices();
syncGroups(initGroupData);
// 改變寬高
$('#changeArea').on('click', function () {
changeArea();
});
// 重置畫布大小
areaScaleDom.on('click', '.reset', function (event) {
event.preventDefault();
changeAreaScale(1);
});
// 縮小畫布
areaScaleDom.on('click', '.narrow', function (event) {
event.preventDefault();
var prevScale = Number(areaScaleDom.attr('data-scale'));
if (prevScale <= 0.25) {
alert('不能再縮小了');
return;
}
changeAreaScale(Math.floor((prevScale / 2) * 100) / 100);
});
// 放大畫布
areaScaleDom.on('click', '.enlarge', function (event) {
event.preventDefault();
var prevScale = Number(areaScaleDom.attr('data-scale'));
if (prevScale > 20) {
alert('不能再放大了');
return;
}
changeAreaScale(Math.floor((prevScale * 2) * 100) / 100);
});
// 設置背景圖片透明度
$('#opacity').on('change', function (e) {
e.preventDefault();
mainDom.css('background-color', 'rgba(255, 255, 255, ' + this.value + ')');
});
// 設置背景圖片
$('#backgroundImage').on('change', function (e) {
e.preventDefault();
var file = this.files[0];
if (file) {
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function () {
var imgSrc = this.result;
backgroundImageDivDom.css('background-image', 'url(' + imgSrc + ')');
};
}
});
// 顯示二維碼模態框
$('body').on('click', '.show-qr-code', function (e) {
e.preventDefault();
// 設備ID
var id = this.parentNode.parentNode.getAttribute('data-id');
$('#QRModal').show();
});
var QRModalDom = $('#QRModal');
var qrcodeDom = $('#qrcode');
// 隱藏二維碼模態框
QRModalDom.on('click', '.close', function (e) {
$('#QRModal').hide();
});
// 縮小
QRModalDom.on('click', '.narrow', function (e) {
var width = qrcodeDom.width();
if (width > 100) {
qrcodeDom.width(width / 2);
}
});
// 放大
QRModalDom.on('click', '.enlarge', function (e) {
var width = qrcodeDom.width() * 2;
if (width < $(window).width()) {
qrcodeDom.width(width);
}
});
// 顯示新增設備模態框
$('#showAddDeviceBtn').on('click', function () {
addDeviceModalDom.show();
});
// 關閉新增設備模態框
$('#closeAddDeviceBtn').on('click', function () {
closeAddDeviceModal();
});
// 新增設備
$('#AddDeviceBtn').on('click', function () {
var deviceName = $('#deviceName').val();
var deviceType = $('#deviceTypeSelect').val();
var devicePosition = $('#devicePositionSelect').val();
if (!deviceName) {
alert('請填寫設備名稱');
return;
}
if (!deviceType) {
alert('請選擇設備類型');
return;
}
if (!devicePosition) {
alert('請選擇設備位置');
return;
}
var device = {
id: deviceSerialNumber++,
name: deviceName,
type: deviceType,
devicePosition: devicePosition,
};
devices[device.id] = device;
syncDevices();
closeAddDeviceModal();
});
// 鼠標移入顯示設備按鈕
deviceListWrapperDom.on('mouseenter', '.show-location', function (event) {
event.preventDefault();
hiddenMainDeviceListModal();
var parentNode = this.parentNode.parentNode;
var id = parentNode.getAttribute('data-id');
debugger;
var device = devices[id];
var groupId = device.groupId;
var groupDom = document.querySelector('#main div[data-group-id="' + groupId + '"]');
if (groupDom) {
groupDom.classList.add('highlight');
groupDom.appendChild($('<p>在這</p>')[0]);
}
});
// 鼠標移出顯示設備按鈕
deviceListWrapperDom.on('mouseleave', '.show-location', function (event) {
event.preventDefault();
var parentNode = this.parentNode.parentNode;
var id = parentNode.getAttribute('data-id');
var device = devices[id];
var groupId = device.groupId;
var groupDom = document.querySelector('#main div[data-group-id="' + groupId + '"]');
if (groupDom) {
groupDom.classList.remove('highlight');
groupDom.querySelector('p').remove();
}
});
// 刪除設備按鈕
deviceListWrapperDom.on('click', '.delete', function (e) {
e.preventDefault();
var wrapperDom = this.parentNode.parentNode;
var id = wrapperDom.getAttribute('data-id');
var obj = devices[id];
if (obj) {
// 根據ID查詢,如果存在對應的選項,則從device中刪除,並釋放拖拽對象
var groupId = obj.groupId;
if (groupId) {
obj.groupId = null;
var total = 0;
for (var key in devices) {
var device = devices[key];
if (device.groupId == groupId) {
total += 1;
}
}
hiddenMainDeviceListModal();
var dom = mainDom.find('div[data-group-id="' + groupId + '"]');
if (total > 0) {
dom.html(total);
} else {
dom[0].remove();
}
}
}
wrapperDom.remove();
});
});
</script>
</body>
</html>