junjiro1129 commited on
Commit
15a00c8
·
verified ·
1 Parent(s): 96730f8

Upload 7 files

Browse files
.gitattributes CHANGED
@@ -33,3 +33,8 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ demokit/bases/bag_sumple.jpg filter=lfs diff=lfs merge=lfs -text
37
+ demokit/bases/mockup_base.png filter=lfs diff=lfs merge=lfs -text
38
+ demokit/designs/sample_design1.jpg filter=lfs diff=lfs merge=lfs -text
39
+ demokit/designs/sample_design2.png filter=lfs diff=lfs merge=lfs -text
40
+ demokit/mockup_web_demo.mp4 filter=lfs diff=lfs merge=lfs -text
coordinatemaker.html ADDED
@@ -0,0 +1,655 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Coordinate Maker</title>
6
+ <style>
7
+ #img-container {
8
+ position: relative;
9
+ width: 800px;
10
+ height: 600px;
11
+ border: 2px dashed #aaa;
12
+ background: #f9f9f9;
13
+ user-select: none;
14
+ display: inline-block;
15
+ overflow: hidden;
16
+ transition: border-color 0.2s, background 0.2s;
17
+ }
18
+ #img-container.dragover {
19
+ border-color: #2a7;
20
+ background: #e2ffe9;
21
+ }
22
+ #the-img {
23
+ width: 100%;
24
+ height: 100%;
25
+ object-fit: contain;
26
+ user-select: none;
27
+ pointer-events: none;
28
+ display: none;
29
+ }
30
+ .rect {
31
+ position: absolute;
32
+ border: 2px solid #2a7;
33
+ background: rgba(44,222,88,0.15);
34
+ box-sizing: border-box;
35
+ cursor: move;
36
+ }
37
+ .rect.selected {
38
+ border: 2px solid #f00;
39
+ background: rgba(255,100,100,0.15);
40
+ z-index: 10;
41
+ }
42
+ .handle {
43
+ position: absolute;
44
+ width: 12px; height: 12px;
45
+ background: #2a7;
46
+ border-radius: 50%;
47
+ cursor: pointer;
48
+ margin: -6px 0 0 -6px;
49
+ z-index: 20;
50
+ border: 1px solid #fff;
51
+ box-shadow: 0 0 2px #0004;
52
+ display: none;
53
+ }
54
+ .rect.selected .handle {
55
+ display: block;
56
+ }
57
+ #coords {
58
+ font-family: monospace;
59
+ margin-top: 10px;
60
+ background: #f8f8f8;
61
+ padding: 10px;
62
+ border: 1px solid #bbb;
63
+ width: 480px;
64
+ min-height: 120px;
65
+ }
66
+ #drop-message {
67
+ position: absolute;
68
+ top: 50%;
69
+ left: 50%;
70
+ width: 90%;
71
+ transform: translate(-50%, -50%);
72
+ color: #2a7;
73
+ font-size: 1.6em;
74
+ text-align: center;
75
+ pointer-events: none;
76
+ display: none;
77
+ background: rgba(255,255,255,0.75);
78
+ border-radius: 10px;
79
+ padding: 0.5em 0;
80
+ z-index: 1000;
81
+ }
82
+ #toolbar {
83
+ margin-bottom: 0.5em;
84
+ display: flex;
85
+ align-items: center;
86
+ flex-wrap: wrap;
87
+ gap: 0.5em;
88
+ }
89
+ #toolbar button, #toolbar input[type="file"] {
90
+ margin-right: 1em;
91
+ padding: 0.5em 1em;
92
+ font-size: 1em;
93
+ cursor: pointer;
94
+ }
95
+ #filename-input {
96
+ padding: 0.5em 1em;
97
+ font-size: 1em;
98
+ width: 220px;
99
+ margin-right: 1em;
100
+ }
101
+ #file-name-label {
102
+ font-size: 0.98em;
103
+ margin-right: 1em;
104
+ color: #333;
105
+ min-width: 120px;
106
+ max-width: 220px;
107
+ overflow: hidden;
108
+ text-overflow: ellipsis;
109
+ white-space: nowrap;
110
+ display: inline-block;
111
+ vertical-align: middle;
112
+ }
113
+ #memory-list {
114
+ margin-top: 1em;
115
+ font-family: monospace;
116
+ font-size: 1em;
117
+ background: #fff;
118
+ border: 1px solid #bbb;
119
+ padding: 8px 12px;
120
+ width: 480px;
121
+ min-height: 40px;
122
+ }
123
+ .memory-item {
124
+ margin-bottom: 0.5em;
125
+ border-bottom: 1px dotted #ccc;
126
+ padding-bottom: 0.3em;
127
+ display: flex;
128
+ align-items: center;
129
+ justify-content: space-between;
130
+ }
131
+ .memory-item:last-child {
132
+ border-bottom: none;
133
+ }
134
+ .memory-item .memory-label {
135
+ display: inline-block;
136
+ max-width: 360px;
137
+ word-break: break-all;
138
+ }
139
+ .memory-item .memory-delete-btn {
140
+ color: #c00;
141
+ background: transparent;
142
+ border: none;
143
+ cursor: pointer;
144
+ margin-left: 1em;
145
+ font-size: 1.1em;
146
+ }
147
+ #add-rect-btn, #save-rect-btn, #memory-save-btn {
148
+ margin-right: 1em;
149
+ padding: 0.5em 1em;
150
+ font-size: 1em;
151
+ cursor: pointer;
152
+ }
153
+ #save-rect-btn:disabled {
154
+ color: #ccc;
155
+ border-color: #ccc;
156
+ cursor: default;
157
+ }
158
+ #rect-list {
159
+ display: none;
160
+ }
161
+ input[type="file"]::-webkit-file-upload-button { visibility: visible; }
162
+ input[type="file"]::file-selector-button { visibility: visible; }
163
+ input[type="file"]::-ms-value { display: none; }
164
+ input[type="file"]::-webkit-file-upload-button,
165
+ input[type="file"]::before {
166
+ content: none !important;
167
+ }
168
+ input[type="file"] {
169
+ color: transparent;
170
+ }
171
+ </style>
172
+ </head>
173
+ <body>
174
+ <h2>Coordinate Maker</h2>
175
+ <div id="toolbar">
176
+ <label style="display:inline-block; position:relative;">
177
+ <input type="file" id="img-input" accept="image/*" style="width:140px;">
178
+ </label>
179
+ <span id="file-name-label"></span>
180
+ <button id="add-rect-btn">Add Rectangle</button>
181
+ <button id="save-rect-btn" disabled>Save Rectangle</button>
182
+ <input type="text" id="filename-input" placeholder="templates.json">
183
+ <button id="memory-save-btn">Save Memory to File</button>
184
+ </div>
185
+ <div id="img-container">
186
+ <span id="drop-message">Drop image here</span>
187
+ <img id="the-img">
188
+ </div>
189
+ <div id="coords">Coordinates:<br></div>
190
+ <div id="memory-list"></div>
191
+ <script>
192
+ const imgInput = document.getElementById('img-input');
193
+ const img = document.getElementById('the-img');
194
+ const container = document.getElementById('img-container');
195
+ const coords = document.getElementById('coords');
196
+ const dropMessage = document.getElementById('drop-message');
197
+ const addRectBtn = document.getElementById('add-rect-btn');
198
+ const saveRectBtn = document.getElementById('save-rect-btn');
199
+ const memorySaveBtn = document.getElementById('memory-save-btn');
200
+ const memoryList = document.getElementById('memory-list');
201
+ const filenameInput = document.getElementById('filename-input');
202
+ const fileNameLabel = document.getElementById('file-name-label');
203
+
204
+ let imgLoaded = false;
205
+ let imgNaturalWidth = 0, imgNaturalHeight = 0;
206
+ let dispImgInfo = {left:0, top:0, width:0, height:0};
207
+ let currentImageName = '';
208
+ let rectObj = null;
209
+ let drawing = false;
210
+ let moving = false;
211
+ let resizing = false;
212
+ let startX = 0, startY = 0;
213
+ let offsetX = 0, offsetY = 0;
214
+ let originX = 0, originY = 0;
215
+ let activeHandle = null;
216
+ let memory = [];
217
+
218
+ function updateFileNameLabel(name) {
219
+ fileNameLabel.textContent = name ? name : "";
220
+ }
221
+
222
+ function loadImageFromFile(file) {
223
+ if (!file || !file.type.match(/^image\//)) return;
224
+ const reader = new FileReader();
225
+ reader.onload = function(ev) {
226
+ img.src = ev.target.result;
227
+ currentImageName = file.name || '';
228
+ updateFileNameLabel(currentImageName);
229
+ };
230
+ reader.readAsDataURL(file);
231
+ }
232
+
233
+ imgInput.addEventListener('change', e => {
234
+ const file = e.target.files[0];
235
+ imgInput.value = "";
236
+ updateFileNameLabel(""); // Clear previous file name immediately
237
+ if (file) {
238
+ loadImageFromFile(file);
239
+ }
240
+ });
241
+
242
+ container.addEventListener('dragover', (e) => {
243
+ e.preventDefault();
244
+ e.stopPropagation();
245
+ container.classList.add('dragover');
246
+ dropMessage.style.display = 'block';
247
+ });
248
+ container.addEventListener('dragleave', (e) => {
249
+ e.preventDefault();
250
+ e.stopPropagation();
251
+ container.classList.remove('dragover');
252
+ dropMessage.style.display = 'none';
253
+ });
254
+ container.addEventListener('drop', (e) => {
255
+ e.preventDefault();
256
+ e.stopPropagation();
257
+ container.classList.remove('dragover');
258
+ dropMessage.style.display = 'none';
259
+ if (e.dataTransfer.files && e.dataTransfer.files[0]) {
260
+ const file = e.dataTransfer.files[0];
261
+ updateFileNameLabel(""); // Clear previous name immediately
262
+ loadImageFromFile(file);
263
+ }
264
+ });
265
+
266
+ img.addEventListener('load', () => {
267
+ imgLoaded = true;
268
+ img.style.display = "block";
269
+ imgNaturalWidth = img.naturalWidth;
270
+ imgNaturalHeight = img.naturalHeight;
271
+ img.style.width = '100%';
272
+ img.style.height = '100%';
273
+ img.style.objectFit = 'contain';
274
+ clearRect();
275
+ updateDispImgInfo();
276
+ updateCoords();
277
+ });
278
+
279
+ function updateDispImgInfo() {
280
+ const cW = container.clientWidth;
281
+ const cH = container.clientHeight;
282
+ const iW = imgNaturalWidth;
283
+ const iH = imgNaturalHeight;
284
+ let dispW = cW, dispH = cH, dispL = 0, dispT = 0;
285
+ const imgAspect = iW / iH;
286
+ const contAspect = cW / cH;
287
+ if (imgAspect > contAspect) {
288
+ dispW = cW;
289
+ dispH = cW / imgAspect;
290
+ dispT = (cH - dispH) / 2;
291
+ dispL = 0;
292
+ } else {
293
+ dispH = cH;
294
+ dispW = cH * imgAspect;
295
+ dispL = (cW - dispW) / 2;
296
+ dispT = 0;
297
+ }
298
+ dispImgInfo = {left:dispL, top:dispT, width:dispW, height:dispH};
299
+ }
300
+ window.addEventListener('resize', updateDispImgInfo);
301
+
302
+ addRectBtn.addEventListener('click', () => {
303
+ if (!imgLoaded) return;
304
+ if (rectObj) return;
305
+ drawing = true;
306
+ setSelectedRect(true);
307
+ coords.innerHTML = "Draw a rectangle on the image.<br>";
308
+ saveRectBtn.disabled = true;
309
+ });
310
+
311
+ saveRectBtn.addEventListener('click', () => {
312
+ if (!rectObj) return;
313
+ const imgPoints = getRectImageCoords(rectObj);
314
+ memory.push({
315
+ filename: currentImageName || '',
316
+ coords: imgPoints,
317
+ id: Date.now() + Math.random()
318
+ });
319
+ updateMemoryList();
320
+ clearRect();
321
+ coords.innerHTML = "Coordinates:<br>";
322
+ saveRectBtn.disabled = true;
323
+ });
324
+
325
+ function clearRect() {
326
+ if (rectObj && rectObj.element) rectObj.element.remove();
327
+ rectObj = null;
328
+ setSelectedRect(false);
329
+ }
330
+
331
+ container.addEventListener('mousedown', (e) => {
332
+ if (!imgLoaded) return;
333
+ if (!drawing) return;
334
+ if (rectObj) return;
335
+ if (e.target !== container && e.target !== img) return;
336
+ const rectC = container.getBoundingClientRect();
337
+ startX = e.clientX - rectC.left;
338
+ startY = e.clientY - rectC.top;
339
+ let rectEl = document.createElement('div');
340
+ rectEl.className = 'rect selected';
341
+ container.appendChild(rectEl);
342
+ rectObj = {
343
+ left: startX, top: startY, width: 0, height: 0,
344
+ element: rectEl, handles: []
345
+ };
346
+ setSelectedRect(true);
347
+ updateRectUI(rectObj);
348
+ document.body.style.cursor = "crosshair";
349
+ drawing = true;
350
+ function onMouseMove(ev) {
351
+ const currX = ev.clientX - rectC.left;
352
+ const currY = ev.clientY - rectC.top;
353
+ rectObj.left = Math.min(startX, currX);
354
+ rectObj.top = Math.min(startY, currY);
355
+ rectObj.width = Math.abs(currX - startX);
356
+ rectObj.height = Math.abs(currY - startY);
357
+ updateRectUI(rectObj);
358
+ updateCoords(rectObj);
359
+ }
360
+ function onMouseUp(ev) {
361
+ drawing = false;
362
+ document.body.style.cursor = "";
363
+ document.removeEventListener('mousemove', onMouseMove);
364
+ document.removeEventListener('mouseup', onMouseUp);
365
+ if (rectObj.width < 10 || rectObj.height < 10) {
366
+ clearRect();
367
+ saveRectBtn.disabled = true;
368
+ } else {
369
+ createHandles(rectObj);
370
+ updateCoords(rectObj);
371
+ saveRectBtn.disabled = false;
372
+ }
373
+ }
374
+ document.addEventListener('mousemove', onMouseMove);
375
+ document.addEventListener('mouseup', onMouseUp);
376
+ e.preventDefault();
377
+ });
378
+
379
+ container.addEventListener('mousedown', (e) => {
380
+ if (drawing) return;
381
+ if (!imgLoaded) return;
382
+ if (!rectObj || !rectObj.element) return;
383
+ if (e.target === rectObj.element) {
384
+ setSelectedRect(true);
385
+ saveRectBtn.disabled = false;
386
+ moving = true;
387
+ const rectC = container.getBoundingClientRect();
388
+ offsetX = e.clientX - rectC.left - rectObj.left;
389
+ offsetY = e.clientY - rectC.top - rectObj.top;
390
+ document.body.style.cursor = "move";
391
+ function onMove(ev) {
392
+ let newLeft = ev.clientX - rectC.left - offsetX;
393
+ let newTop = ev.clientY - rectC.top - offsetY;
394
+ newLeft = Math.max(0, Math.min(newLeft, container.clientWidth - rectObj.width));
395
+ newTop = Math.max(0, Math.min(newTop, container.clientHeight - rectObj.height));
396
+ rectObj.left = newLeft;
397
+ rectObj.top = newTop;
398
+ updateRectUI(rectObj);
399
+ updateHandles(rectObj);
400
+ updateCoords(rectObj);
401
+ }
402
+ function onUp(ev) {
403
+ moving = false;
404
+ document.body.style.cursor = "";
405
+ document.removeEventListener('mousemove', onMove);
406
+ document.removeEventListener('mouseup', onUp);
407
+ }
408
+ document.addEventListener('mousemove', onMove);
409
+ document.addEventListener('mouseup', onUp);
410
+ e.stopPropagation();
411
+ }
412
+ });
413
+
414
+ function createHandles(rectObj) {
415
+ if (rectObj.handles && rectObj.handles.length) {
416
+ rectObj.handles.forEach(h=>h.remove());
417
+ }
418
+ const positions = ['tl','tr','br','bl'];
419
+ rectObj.handles = [];
420
+ for(let i=0; i<4; i++) {
421
+ let h = document.createElement('div');
422
+ h.className = 'handle';
423
+ h.dataset.handle = positions[i];
424
+ h.style.cursor = handleCursor(positions[i]);
425
+ h.addEventListener('mousedown', (e) => {
426
+ resizing = true;
427
+ activeHandle = positions[i];
428
+ originX = e.clientX;
429
+ originY = e.clientY;
430
+ h._orig = {...rectObj};
431
+ document.body.style.cursor = h.style.cursor;
432
+ function onMove(ev) {
433
+ resizeRect(rectObj, ev, h._orig);
434
+ updateRectUI(rectObj);
435
+ updateHandles(rectObj);
436
+ updateCoords(rectObj);
437
+ }
438
+ function onUp(ev) {
439
+ resizing = false;
440
+ document.body.style.cursor = "";
441
+ document.removeEventListener('mousemove', onMove);
442
+ document.removeEventListener('mouseup', onUp);
443
+ }
444
+ document.addEventListener('mousemove', onMove);
445
+ document.addEventListener('mouseup', onUp);
446
+ e.stopPropagation();
447
+ });
448
+ rectObj.element.appendChild(h);
449
+ rectObj.handles.push(h);
450
+ }
451
+ updateHandles(rectObj);
452
+ }
453
+ function handleCursor(pos) {
454
+ switch(pos) {
455
+ case 'tl': return 'nwse-resize';
456
+ case 'tr': return 'nesw-resize';
457
+ case 'br': return 'nwse-resize';
458
+ case 'bl': return 'nesw-resize';
459
+ default: return 'pointer';
460
+ }
461
+ }
462
+ function updateHandles(rectObj) {
463
+ const {width, height, handles} = rectObj;
464
+ if(!handles || handles.length!==4) return;
465
+ handles[0].style.left = '0px';
466
+ handles[0].style.top = '0px';
467
+ handles[1].style.left = width + 'px';
468
+ handles[1].style.top = '0px';
469
+ handles[2].style.left = width + 'px';
470
+ handles[2].style.top = height + 'px';
471
+ handles[3].style.left = '0px';
472
+ handles[3].style.top = height + 'px';
473
+ }
474
+ function resizeRect(rectObj, e, orig) {
475
+ let dx = e.clientX - originX;
476
+ let dy = e.clientY - originY;
477
+ let nd = {...orig};
478
+ switch(activeHandle) {
479
+ case 'tl':
480
+ nd.left = Math.min(orig.left + dx, orig.left + orig.width - 10);
481
+ nd.top = Math.min(orig.top + dy, orig.top + orig.height - 10);
482
+ nd.width = orig.width - (nd.left - orig.left);
483
+ nd.height = orig.height - (nd.top - orig.top);
484
+ break;
485
+ case 'tr':
486
+ nd.top = Math.min(orig.top + dy, orig.top + orig.height - 10);
487
+ nd.width = Math.max(10, orig.width + dx);
488
+ nd.height = orig.height - (nd.top - orig.top);
489
+ nd.left = orig.left;
490
+ break;
491
+ case 'br':
492
+ nd.width = Math.max(10, orig.width + dx);
493
+ nd.height = Math.max(10, orig.height + dy);
494
+ nd.left = orig.left;
495
+ nd.top = orig.top;
496
+ break;
497
+ case 'bl':
498
+ nd.left = Math.min(orig.left + dx, orig.left + orig.width - 10);
499
+ nd.width = orig.width - (nd.left - orig.left);
500
+ nd.height = Math.max(10, orig.height + dy);
501
+ nd.top = orig.top;
502
+ break;
503
+ }
504
+ nd.left = Math.max(0, Math.min(nd.left, container.clientWidth - nd.width));
505
+ nd.top = Math.max(0, Math.min(nd.top, container.clientHeight - nd.height));
506
+ nd.width = Math.max(10, Math.min(nd.width, container.clientWidth - nd.left));
507
+ nd.height = Math.max(10, Math.min(nd.height, container.clientHeight - nd.top));
508
+ Object.assign(rectObj, nd);
509
+ }
510
+ function updateRectUI(rectObj) {
511
+ rectObj.element.style.left = rectObj.left + 'px';
512
+ rectObj.element.style.top = rectObj.top + 'px';
513
+ rectObj.element.style.width = rectObj.width + 'px';
514
+ rectObj.element.style.height = rectObj.height + 'px';
515
+ rectObj.element.classList.add('selected');
516
+ }
517
+
518
+ function setSelectedRect(selected) {
519
+ if (rectObj && rectObj.element) {
520
+ if (selected) {
521
+ rectObj.element.classList.add('selected');
522
+ } else {
523
+ rectObj.element.classList.remove('selected');
524
+ }
525
+ }
526
+ saveRectBtn.disabled = !rectObj;
527
+ }
528
+
529
+ function getRectImageCoords(rectObj) {
530
+ const {left:imgL, top:imgT, width:imgW, height:imgH} = dispImgInfo;
531
+ const clamp = (v, min, max) => Math.max(min, Math.min(v, max));
532
+ const dispPoints = [
533
+ { x: clamp(rectObj.left, imgL, imgL+imgW), y: clamp(rectObj.top, imgT, imgT+imgH) },
534
+ { x: clamp(rectObj.left+rectObj.width, imgL, imgL+imgW), y: clamp(rectObj.top, imgT, imgT+imgH) },
535
+ { x: clamp(rectObj.left+rectObj.width, imgL, imgL+imgW), y: clamp(rectObj.top+rectObj.height, imgT, imgT+imgH) },
536
+ { x: clamp(rectObj.left, imgL, imgL+imgW), y: clamp(rectObj.top+rectObj.height, imgT, imgT+imgH) }
537
+ ];
538
+ const toImgPx = (p) => [
539
+ Math.round( (p.x - imgL) * imgNaturalWidth / imgW ),
540
+ Math.round( (p.y - imgT) * imgNaturalHeight / imgH )
541
+ ];
542
+ return dispPoints.map(toImgPx);
543
+ }
544
+
545
+ function updateCoords(rectObj) {
546
+ if (!rectObj) {
547
+ coords.innerHTML = "Coordinates:<br>";
548
+ return;
549
+ }
550
+ const imgPoints = getRectImageCoords(rectObj);
551
+ coords.innerHTML =
552
+ `Original image pixel coordinates (top-left origin):<br>
553
+ 1. (${imgPoints[0][0]}, ${imgPoints[0][1]})<br>
554
+ 2. (${imgPoints[1][0]}, ${imgPoints[1][1]})<br>
555
+ 3. (${imgPoints[2][0]}, ${imgPoints[2][1]})<br>
556
+ 4. (${imgPoints[3][0]}, ${imgPoints[3][1]})<br>`;
557
+ }
558
+
559
+ function updateMemoryList() {
560
+ let html = '';
561
+ memory.forEach((mem, idx) => {
562
+ html += `<div class="memory-item" data-id="${mem.id}">
563
+ <span class="memory-label"><b>${mem.filename}</b> :
564
+ TL(${mem.coords[0][0]},${mem.coords[0][1]})
565
+ TR(${mem.coords[1][0]},${mem.coords[1][1]})
566
+ BR(${mem.coords[2][0]},${mem.coords[2][1]})
567
+ BL(${mem.coords[3][0]},${mem.coords[3][1]})
568
+ </span>
569
+ <button class="memory-delete-btn" data-id="${mem.id}" title="Delete this memory">&times;</button>
570
+ </div>`;
571
+ });
572
+ memoryList.innerHTML = html || "<span style='color:#999;'>No memory saved.</span>";
573
+ }
574
+
575
+ memoryList.addEventListener('click', (e) => {
576
+ if (e.target.classList.contains('memory-delete-btn')) {
577
+ const id = e.target.dataset.id;
578
+ memory = memory.filter(m => m.id != id);
579
+ updateMemoryList();
580
+ }
581
+ });
582
+
583
+ // Save memory to JSON file using the File System Access API if available (showSaveFilePicker)
584
+ memorySaveBtn.addEventListener('click', async () => {
585
+ if (!memory.length) {
586
+ alert("No memory to save.");
587
+ return;
588
+ }
589
+ // Convert memory to required JSON format
590
+ // { "filename": { "print_area": [[x,y], ...] }, ... }
591
+ let outObj = {};
592
+ memory.forEach(mem => {
593
+ outObj[mem.filename] = {
594
+ print_area: mem.coords
595
+ };
596
+ });
597
+ let jsonString = JSON.stringify(outObj, null, 2);
598
+
599
+ let filename = filenameInput.value.trim() || "templates.json";
600
+ filename = filename.replace(/[\\\/:*?"<>|]/g, "_");
601
+
602
+ // Prefer File System Access API if available
603
+ if (window.showSaveFilePicker) {
604
+ try {
605
+ const opts = {
606
+ suggestedName: filename,
607
+ types: [
608
+ {
609
+ description: 'JSON Files',
610
+ accept: {'application/json': ['.json', '.txt']}
611
+ }
612
+ ]
613
+ };
614
+ const handle = await window.showSaveFilePicker(opts);
615
+ const writable = await handle.createWritable();
616
+ await writable.write(jsonString);
617
+ await writable.close();
618
+ alert("Memory saved!");
619
+ return;
620
+ } catch (err) {
621
+ if (err.name !== "AbortError") {
622
+ alert("Failed to save file: " + err.message);
623
+ }
624
+ }
625
+ }
626
+
627
+ // Fallback: Classic download
628
+ const blob = new Blob([jsonString], {type: "application/json"});
629
+ const url = URL.createObjectURL(blob);
630
+ const a = document.createElement('a');
631
+ a.href = url;
632
+ a.download = filename;
633
+ document.body.appendChild(a);
634
+ a.click();
635
+ setTimeout(() => {
636
+ document.body.removeChild(a);
637
+ URL.revokeObjectURL(url);
638
+ }, 100);
639
+ });
640
+
641
+ document.addEventListener('keydown', e => {
642
+ if ((e.key === "Delete" || e.key === "Backspace") && rectObj) {
643
+ clearRect();
644
+ setSelectedRect(false);
645
+ coords.innerHTML = "Coordinates:<br>";
646
+ saveRectBtn.disabled = true;
647
+ }
648
+ });
649
+
650
+ coords.innerHTML = "Coordinates:<br>";
651
+ updateMemoryList();
652
+ updateFileNameLabel("");
653
+ </script>
654
+ </body>
655
+ </html>
demokit/bases/bag_sumple.jpg ADDED

Git LFS Details

  • SHA256: 116bff77641b870a8e6a8e96b7552b39605040cc5ae1d990c98cee5bc0f2fd9e
  • Pointer size: 133 Bytes
  • Size of remote file: 14.5 MB
demokit/bases/mockup_base.png ADDED

Git LFS Details

  • SHA256: 113383a3f071e7773c3f690126f219295c6b12d62ab8bfd2e9faeebf98b48dcd
  • Pointer size: 131 Bytes
  • Size of remote file: 178 kB
demokit/designs/sample_design1.jpg ADDED

Git LFS Details

  • SHA256: 903b50d79a245e2a64e32552fddc88add85a4c714e5314c937f50f17af5758c4
  • Pointer size: 132 Bytes
  • Size of remote file: 1.67 MB
demokit/designs/sample_design2.png ADDED

Git LFS Details

  • SHA256: 297eaa6373b703fc68e8b3f428206efafede057af821c9ee1ce1008f7d6e6e8f
  • Pointer size: 132 Bytes
  • Size of remote file: 3.74 MB
demokit/mockup_web_demo.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:18f26e700bbbd74ca40fb4e3371334444e5394ce587e1f21860c2596f3d01f04
3
+ size 26592516
demokit/templates.json ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "bag_sumple.jpg": {
3
+ "print_area": [
4
+ [
5
+ 1315,
6
+ 1391
7
+ ],
8
+ [
9
+ 3289,
10
+ 1391
11
+ ],
12
+ [
13
+ 3289,
14
+ 3538
15
+ ],
16
+ [
17
+ 1315,
18
+ 3538
19
+ ]
20
+ ]
21
+ },
22
+ "mockup_base.png": {
23
+ "print_area": [
24
+ [
25
+ 210,
26
+ 187
27
+ ],
28
+ [
29
+ 412,
30
+ 187
31
+ ],
32
+ [
33
+ 412,
34
+ 519
35
+ ],
36
+ [
37
+ 210,
38
+ 519
39
+ ]
40
+ ]
41
+ }
42
+ }