@wasao/kagemusha 0.1.1 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +168 -79
- package/dist/commands/add.d.ts +6 -0
- package/dist/commands/add.d.ts.map +1 -0
- package/dist/commands/add.js +26 -0
- package/dist/commands/add.js.map +1 -0
- package/dist/commands/capture.d.ts +3 -2
- package/dist/commands/capture.d.ts.map +1 -1
- package/dist/commands/capture.js +256 -20
- package/dist/commands/capture.js.map +1 -1
- package/dist/commands/discover.d.ts +2 -0
- package/dist/commands/discover.d.ts.map +1 -0
- package/dist/commands/discover.js +62 -0
- package/dist/commands/discover.js.map +1 -0
- package/dist/commands/edit.d.ts +1 -1
- package/dist/commands/edit.d.ts.map +1 -1
- package/dist/commands/edit.js +82 -26
- package/dist/commands/edit.js.map +1 -1
- package/dist/commands/init.d.ts +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +240 -105
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/list.d.ts +2 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +33 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/login.d.ts +6 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +131 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/validate.js +1 -1
- package/dist/commands/validate.js.map +1 -1
- package/dist/editor/inject-script/annotations.d.ts +11 -0
- package/dist/editor/inject-script/annotations.d.ts.map +1 -0
- package/dist/editor/inject-script/annotations.js +409 -0
- package/dist/editor/inject-script/annotations.js.map +1 -0
- package/dist/editor/inject-script/bridge.d.ts +13 -0
- package/dist/editor/inject-script/bridge.d.ts.map +1 -0
- package/dist/editor/inject-script/bridge.js +33 -0
- package/dist/editor/inject-script/bridge.js.map +1 -0
- package/dist/editor/inject-script/crop.d.ts +9 -0
- package/dist/editor/inject-script/crop.d.ts.map +1 -0
- package/dist/editor/inject-script/crop.js +236 -0
- package/dist/editor/inject-script/crop.js.map +1 -0
- package/dist/editor/inject-script/dom.d.ts +7 -0
- package/dist/editor/inject-script/dom.d.ts.map +1 -0
- package/dist/editor/inject-script/dom.js +32 -0
- package/dist/editor/inject-script/dom.js.map +1 -0
- package/dist/editor/inject-script/index.d.ts +2 -0
- package/dist/editor/inject-script/index.d.ts.map +1 -0
- package/dist/editor/inject-script/index.js +56 -0
- package/dist/editor/inject-script/index.js.map +1 -0
- package/dist/editor/inject-script/record.d.ts +5 -0
- package/dist/editor/inject-script/record.d.ts.map +1 -0
- package/dist/editor/inject-script/record.js +398 -0
- package/dist/editor/inject-script/record.js.map +1 -0
- package/dist/editor/inject-script/selector.d.ts +6 -0
- package/dist/editor/inject-script/selector.d.ts.map +1 -0
- package/dist/editor/inject-script/selector.js +112 -0
- package/dist/editor/inject-script/selector.js.map +1 -0
- package/dist/editor/inject-script/state.d.ts +27 -0
- package/dist/editor/inject-script/state.d.ts.map +1 -0
- package/dist/editor/inject-script/state.js +26 -0
- package/dist/editor/inject-script/state.js.map +1 -0
- package/dist/editor/inject-script/svg.d.ts +7 -0
- package/dist/editor/inject-script/svg.d.ts.map +1 -0
- package/dist/editor/inject-script/svg.js +39 -0
- package/dist/editor/inject-script/svg.js.map +1 -0
- package/dist/editor/inject-script/toolbar.d.ts +14 -0
- package/dist/editor/inject-script/toolbar.d.ts.map +1 -0
- package/dist/editor/inject-script/toolbar.js +240 -0
- package/dist/editor/inject-script/toolbar.js.map +1 -0
- package/dist/editor/inject-script/types.d.ts +102 -0
- package/dist/editor/inject-script/types.d.ts.map +1 -0
- package/dist/editor/inject-script/types.js +5 -0
- package/dist/editor/inject-script/types.js.map +1 -0
- package/dist/editor/inject-script.js +1276 -353
- package/dist/index.js +34 -16
- package/dist/index.js.map +1 -1
- package/dist/lib/annotate.d.ts +2 -2
- package/dist/lib/annotate.d.ts.map +1 -1
- package/dist/lib/annotate.js +35 -43
- package/dist/lib/annotate.js.map +1 -1
- package/dist/lib/auth.d.ts +18 -0
- package/dist/lib/auth.d.ts.map +1 -0
- package/dist/lib/auth.js +45 -0
- package/dist/lib/auth.js.map +1 -0
- package/dist/lib/aws-error.d.ts +7 -0
- package/dist/lib/aws-error.d.ts.map +1 -0
- package/dist/lib/aws-error.js +74 -0
- package/dist/lib/aws-error.js.map +1 -0
- package/dist/lib/canonical.d.ts +54 -0
- package/dist/lib/canonical.d.ts.map +1 -0
- package/dist/lib/canonical.js +152 -0
- package/dist/lib/canonical.js.map +1 -0
- package/dist/lib/config.d.ts +2 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +23 -13
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/crawl.d.ts +1 -1
- package/dist/lib/crawl.d.ts.map +1 -1
- package/dist/lib/crawl.js +213 -20
- package/dist/lib/crawl.js.map +1 -1
- package/dist/lib/definition.d.ts +2 -0
- package/dist/lib/definition.d.ts.map +1 -0
- package/dist/lib/definition.js +6 -0
- package/dist/lib/definition.js.map +1 -0
- package/dist/lib/diff.d.ts +71 -0
- package/dist/lib/diff.d.ts.map +1 -0
- package/dist/lib/diff.js +40 -0
- package/dist/lib/diff.js.map +1 -0
- package/dist/lib/login-error.d.ts +10 -0
- package/dist/lib/login-error.d.ts.map +1 -0
- package/dist/lib/login-error.js +13 -0
- package/dist/lib/login-error.js.map +1 -0
- package/dist/lib/page-ready.d.ts +18 -0
- package/dist/lib/page-ready.d.ts.map +1 -0
- package/dist/lib/page-ready.js +19 -0
- package/dist/lib/page-ready.js.map +1 -0
- package/dist/lib/screenshot.d.ts +11 -2
- package/dist/lib/screenshot.d.ts.map +1 -1
- package/dist/lib/screenshot.js +73 -64
- package/dist/lib/screenshot.js.map +1 -1
- package/dist/lib/staging.d.ts +7 -0
- package/dist/lib/staging.d.ts.map +1 -0
- package/dist/lib/staging.js +21 -0
- package/dist/lib/staging.js.map +1 -0
- package/dist/types.d.ts +10 -23
- package/dist/types.d.ts.map +1 -1
- package/package.json +20 -3
- package/dist/commands/preview.d.ts +0 -6
- package/dist/commands/preview.d.ts.map +0 -1
- package/dist/commands/preview.js +0 -33
- package/dist/commands/preview.js.map +0 -1
- package/dist/commands/run.d.ts +0 -6
- package/dist/commands/run.d.ts.map +0 -1
- package/dist/commands/run.js +0 -39
- package/dist/commands/run.js.map +0 -1
- package/dist/editor/editor/editor.html +0 -313
- package/dist/editor/editor/inject.ts +0 -385
- package/dist/editor/editor.html +0 -338
- package/dist/editor/inject-script.cjs +0 -398
- package/dist/editor/inject-script.cjs.map +0 -1
- package/dist/editor/inject-script.d.cts +0 -2
- package/dist/editor/inject-script.d.cts.map +0 -1
- package/dist/editor/inject-script.d.ts +0 -2
- package/dist/editor/inject-script.d.ts.map +0 -1
- package/dist/editor/inject-script.js.map +0 -1
- package/dist/editor/inject.d.ts +0 -2
- package/dist/editor/inject.d.ts.map +0 -1
- package/dist/editor/inject.js +0 -385
- package/dist/editor/inject.js.map +0 -1
- package/dist/lib/upload.d.ts +0 -9
- package/dist/lib/upload.d.ts.map +0 -1
- package/dist/lib/upload.js +0 -43
- package/dist/lib/upload.js.map +0 -1
package/dist/editor/editor.html
DELETED
|
@@ -1,338 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<title>Kagemusha Annotation Editor</title>
|
|
6
|
-
<style>
|
|
7
|
-
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
8
|
-
body { background: #1a1a2e; font-family: -apple-system, BlinkMacSystemFont, sans-serif; overflow: hidden; }
|
|
9
|
-
|
|
10
|
-
.toolbar {
|
|
11
|
-
position: fixed; top: 0; left: 0; right: 0; z-index: 100;
|
|
12
|
-
background: #16213e; padding: 8px 16px; display: flex; align-items: center; gap: 12px;
|
|
13
|
-
box-shadow: 0 2px 8px rgba(0,0,0,0.3);
|
|
14
|
-
}
|
|
15
|
-
.toolbar button {
|
|
16
|
-
padding: 6px 14px; border: 1px solid #444; border-radius: 6px;
|
|
17
|
-
background: #1a1a2e; color: #fff; font-size: 13px; cursor: pointer;
|
|
18
|
-
}
|
|
19
|
-
.toolbar button:hover { background: #2a2a4e; }
|
|
20
|
-
.toolbar button.active { background: #6366f1; border-color: #6366f1; }
|
|
21
|
-
.toolbar .separator { width: 1px; height: 24px; background: #444; }
|
|
22
|
-
.toolbar .title { color: #888; font-size: 13px; margin-right: 8px; }
|
|
23
|
-
.toolbar .save-btn { background: #22c55e; border-color: #22c55e; font-weight: 600; margin-left: auto; }
|
|
24
|
-
.toolbar .save-btn:hover { background: #16a34a; }
|
|
25
|
-
|
|
26
|
-
.canvas-area {
|
|
27
|
-
margin-top: 48px; display: flex; justify-content: center; padding: 20px;
|
|
28
|
-
height: calc(100vh - 48px); overflow: auto;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
.editor-container {
|
|
32
|
-
position: relative; display: inline-block; cursor: crosshair;
|
|
33
|
-
}
|
|
34
|
-
.editor-container img { display: block; max-width: 100%; }
|
|
35
|
-
|
|
36
|
-
.annotation {
|
|
37
|
-
position: absolute; cursor: move;
|
|
38
|
-
}
|
|
39
|
-
.annotation.selected { outline: 2px dashed #6366f1; outline-offset: 2px; }
|
|
40
|
-
.annotation .handle {
|
|
41
|
-
position: absolute; width: 8px; height: 8px; background: #6366f1;
|
|
42
|
-
border: 1px solid #fff; border-radius: 2px;
|
|
43
|
-
}
|
|
44
|
-
.annotation .handle-br { bottom: -4px; right: -4px; cursor: se-resize; }
|
|
45
|
-
.annotation .handle-bl { bottom: -4px; left: -4px; cursor: sw-resize; }
|
|
46
|
-
.annotation .handle-tr { top: -4px; right: -4px; cursor: ne-resize; }
|
|
47
|
-
.annotation .handle-tl { top: -4px; left: -4px; cursor: nw-resize; }
|
|
48
|
-
|
|
49
|
-
.label-input {
|
|
50
|
-
background: none; border: none; color: inherit; font: inherit;
|
|
51
|
-
width: 100%; outline: none;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
.hint {
|
|
55
|
-
position: fixed; bottom: 16px; left: 50%; transform: translateX(-50%);
|
|
56
|
-
color: #666; font-size: 12px;
|
|
57
|
-
}
|
|
58
|
-
</style>
|
|
59
|
-
</head>
|
|
60
|
-
<body>
|
|
61
|
-
|
|
62
|
-
<div class="toolbar">
|
|
63
|
-
<span class="title">🥷 Annotation Editor</span>
|
|
64
|
-
<button id="tool-rect" class="active" onclick="setTool('rect')">▭ Rectangle</button>
|
|
65
|
-
<button id="tool-arrow" onclick="setTool('arrow')">→ Arrow</button>
|
|
66
|
-
<button id="tool-label" onclick="setTool('label')">T Label</button>
|
|
67
|
-
<div class="separator"></div>
|
|
68
|
-
<button onclick="deleteSelected()">🗑 Delete</button>
|
|
69
|
-
<button class="save-btn" onclick="save()">💾 Save</button>
|
|
70
|
-
</div>
|
|
71
|
-
|
|
72
|
-
<div class="canvas-area">
|
|
73
|
-
<div class="editor-container" id="editor">
|
|
74
|
-
<img id="screenshot" />
|
|
75
|
-
</div>
|
|
76
|
-
</div>
|
|
77
|
-
|
|
78
|
-
<div class="hint">Click and drag to add annotations. Click to select. Press Delete to remove.</div>
|
|
79
|
-
|
|
80
|
-
<script>
|
|
81
|
-
let tool = 'rect';
|
|
82
|
-
let annotations = [];
|
|
83
|
-
let selectedId = null;
|
|
84
|
-
let dragState = null;
|
|
85
|
-
let nextId = 1;
|
|
86
|
-
|
|
87
|
-
const editor = document.getElementById('editor');
|
|
88
|
-
const img = document.getElementById('screenshot');
|
|
89
|
-
|
|
90
|
-
// Set by Playwright
|
|
91
|
-
window.__SCREENSHOT_PATH__ = '';
|
|
92
|
-
window.__EXISTING_DECORATIONS__ = [];
|
|
93
|
-
|
|
94
|
-
window.initEditor = (screenshotDataUrl, existingDecorations) => {
|
|
95
|
-
img.src = screenshotDataUrl;
|
|
96
|
-
if (existingDecorations) {
|
|
97
|
-
existingDecorations.forEach(d => {
|
|
98
|
-
addAnnotationFromDecoration(d);
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
function setTool(t) {
|
|
104
|
-
tool = t;
|
|
105
|
-
document.querySelectorAll('.toolbar button').forEach(b => b.classList.remove('active'));
|
|
106
|
-
document.getElementById('tool-' + t)?.classList.add('active');
|
|
107
|
-
deselectAll();
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
function deselectAll() {
|
|
111
|
-
selectedId = null;
|
|
112
|
-
document.querySelectorAll('.annotation').forEach(el => el.classList.remove('selected'));
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function deleteSelected() {
|
|
116
|
-
if (!selectedId) return;
|
|
117
|
-
const el = document.querySelector(`[data-id="${selectedId}"]`);
|
|
118
|
-
if (el) el.remove();
|
|
119
|
-
annotations = annotations.filter(a => a.id !== selectedId);
|
|
120
|
-
selectedId = null;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
document.addEventListener('keydown', e => {
|
|
124
|
-
if (e.key === 'Delete' || e.key === 'Backspace') {
|
|
125
|
-
if (document.activeElement.classList?.contains('label-input')) return;
|
|
126
|
-
deleteSelected();
|
|
127
|
-
}
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
editor.addEventListener('mousedown', e => {
|
|
131
|
-
if (e.target.closest('.annotation')) return;
|
|
132
|
-
const rect = editor.getBoundingClientRect();
|
|
133
|
-
const x = e.clientX - rect.left;
|
|
134
|
-
const y = e.clientY - rect.top;
|
|
135
|
-
deselectAll();
|
|
136
|
-
|
|
137
|
-
if (tool === 'rect') {
|
|
138
|
-
dragState = { type: 'create-rect', startX: x, startY: y };
|
|
139
|
-
const el = createRectElement(nextId, x, y, 0, 0);
|
|
140
|
-
editor.appendChild(el);
|
|
141
|
-
dragState.element = el;
|
|
142
|
-
dragState.id = nextId++;
|
|
143
|
-
} else if (tool === 'arrow') {
|
|
144
|
-
dragState = { type: 'create-arrow', startX: x, startY: y };
|
|
145
|
-
const el = createArrowElement(nextId, x, y, x, y);
|
|
146
|
-
editor.appendChild(el);
|
|
147
|
-
dragState.element = el;
|
|
148
|
-
dragState.id = nextId++;
|
|
149
|
-
} else if (tool === 'label') {
|
|
150
|
-
const id = nextId++;
|
|
151
|
-
const annotation = { id, type: 'label', x, y, text: 'Label' };
|
|
152
|
-
annotations.push(annotation);
|
|
153
|
-
const el = createLabelElement(id, x, y, 'Label');
|
|
154
|
-
editor.appendChild(el);
|
|
155
|
-
selectedId = id;
|
|
156
|
-
el.classList.add('selected');
|
|
157
|
-
el.querySelector('.label-input').focus();
|
|
158
|
-
el.querySelector('.label-input').select();
|
|
159
|
-
}
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
document.addEventListener('mousemove', e => {
|
|
163
|
-
if (!dragState) return;
|
|
164
|
-
const rect = editor.getBoundingClientRect();
|
|
165
|
-
const x = e.clientX - rect.left;
|
|
166
|
-
const y = e.clientY - rect.top;
|
|
167
|
-
|
|
168
|
-
if (dragState.type === 'create-rect') {
|
|
169
|
-
const el = dragState.element;
|
|
170
|
-
const w = x - dragState.startX;
|
|
171
|
-
const h = y - dragState.startY;
|
|
172
|
-
el.style.left = (w > 0 ? dragState.startX : x) + 'px';
|
|
173
|
-
el.style.top = (h > 0 ? dragState.startY : y) + 'px';
|
|
174
|
-
el.style.width = Math.abs(w) + 'px';
|
|
175
|
-
el.style.height = Math.abs(h) + 'px';
|
|
176
|
-
} else if (dragState.type === 'create-arrow') {
|
|
177
|
-
updateArrowElement(dragState.element, dragState.startX, dragState.startY, x, y);
|
|
178
|
-
} else if (dragState.type === 'move') {
|
|
179
|
-
const a = annotations.find(a => a.id === dragState.id);
|
|
180
|
-
if (a) {
|
|
181
|
-
if (a.type === 'rect' || a.type === 'label') {
|
|
182
|
-
a.x = x - dragState.offsetX;
|
|
183
|
-
a.y = y - dragState.offsetY;
|
|
184
|
-
dragState.element.style.left = a.x + 'px';
|
|
185
|
-
dragState.element.style.top = a.y + 'px';
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
document.addEventListener('mouseup', e => {
|
|
192
|
-
if (!dragState) return;
|
|
193
|
-
const rect = editor.getBoundingClientRect();
|
|
194
|
-
const x = e.clientX - rect.left;
|
|
195
|
-
const y = e.clientY - rect.top;
|
|
196
|
-
|
|
197
|
-
if (dragState.type === 'create-rect') {
|
|
198
|
-
const w = Math.abs(x - dragState.startX);
|
|
199
|
-
const h = Math.abs(y - dragState.startY);
|
|
200
|
-
if (w < 5 && h < 5) {
|
|
201
|
-
dragState.element.remove();
|
|
202
|
-
} else {
|
|
203
|
-
const annotation = {
|
|
204
|
-
id: dragState.id, type: 'rect',
|
|
205
|
-
x: Math.min(dragState.startX, x), y: Math.min(dragState.startY, y),
|
|
206
|
-
width: w, height: h
|
|
207
|
-
};
|
|
208
|
-
annotations.push(annotation);
|
|
209
|
-
dragState.element.dataset.id = dragState.id;
|
|
210
|
-
selectedId = dragState.id;
|
|
211
|
-
dragState.element.classList.add('selected');
|
|
212
|
-
}
|
|
213
|
-
} else if (dragState.type === 'create-arrow') {
|
|
214
|
-
const dist = Math.hypot(x - dragState.startX, y - dragState.startY);
|
|
215
|
-
if (dist < 5) {
|
|
216
|
-
dragState.element.remove();
|
|
217
|
-
} else {
|
|
218
|
-
const annotation = {
|
|
219
|
-
id: dragState.id, type: 'arrow',
|
|
220
|
-
fromX: dragState.startX, fromY: dragState.startY,
|
|
221
|
-
toX: x, toY: y
|
|
222
|
-
};
|
|
223
|
-
annotations.push(annotation);
|
|
224
|
-
dragState.element.dataset.id = dragState.id;
|
|
225
|
-
selectedId = dragState.id;
|
|
226
|
-
dragState.element.classList.add('selected');
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
dragState = null;
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
function createRectElement(id, x, y, w, h) {
|
|
233
|
-
const el = document.createElement('div');
|
|
234
|
-
el.className = 'annotation';
|
|
235
|
-
el.dataset.id = id;
|
|
236
|
-
el.style.cssText = `left:${x}px;top:${y}px;width:${w}px;height:${h}px;border:2px solid #FF0000;border-radius:4px;`;
|
|
237
|
-
el.innerHTML = '<div class="handle handle-br"></div>';
|
|
238
|
-
el.addEventListener('mousedown', e => {
|
|
239
|
-
e.stopPropagation();
|
|
240
|
-
selectedId = parseInt(el.dataset.id);
|
|
241
|
-
deselectAll();
|
|
242
|
-
el.classList.add('selected');
|
|
243
|
-
selectedId = parseInt(el.dataset.id);
|
|
244
|
-
const a = annotations.find(a => a.id === selectedId);
|
|
245
|
-
if (a) {
|
|
246
|
-
const rect = editor.getBoundingClientRect();
|
|
247
|
-
dragState = { type: 'move', id: selectedId, element: el, offsetX: e.clientX - rect.left - a.x, offsetY: e.clientY - rect.top - a.y };
|
|
248
|
-
}
|
|
249
|
-
});
|
|
250
|
-
return el;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
function createArrowElement(id, x1, y1, x2, y2) {
|
|
254
|
-
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
255
|
-
svg.classList.add('annotation');
|
|
256
|
-
svg.dataset.id = id;
|
|
257
|
-
svg.style.cssText = 'position:absolute;left:0;top:0;width:100%;height:100%;pointer-events:none;';
|
|
258
|
-
svg.innerHTML = `
|
|
259
|
-
<defs><marker id="ah-${id}" markerWidth="10" markerHeight="7" refX="10" refY="3.5" orient="auto" fill="#FF0000">
|
|
260
|
-
<polygon points="0 0, 10 3.5, 0 7"/></marker></defs>
|
|
261
|
-
<line x1="${x1}" y1="${y1}" x2="${x2}" y2="${y2}" stroke="#FF0000" stroke-width="2" marker-end="url(#ah-${id})" style="pointer-events:stroke;cursor:move;" />
|
|
262
|
-
`;
|
|
263
|
-
svg.querySelector('line').addEventListener('mousedown', e => {
|
|
264
|
-
e.stopPropagation();
|
|
265
|
-
deselectAll();
|
|
266
|
-
selectedId = parseInt(svg.dataset.id);
|
|
267
|
-
svg.classList.add('selected');
|
|
268
|
-
});
|
|
269
|
-
return svg;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
function updateArrowElement(svg, x1, y1, x2, y2) {
|
|
273
|
-
const line = svg.querySelector('line');
|
|
274
|
-
line.setAttribute('x1', x1);
|
|
275
|
-
line.setAttribute('y1', y1);
|
|
276
|
-
line.setAttribute('x2', x2);
|
|
277
|
-
line.setAttribute('y2', y2);
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
function createLabelElement(id, x, y, text) {
|
|
281
|
-
const el = document.createElement('div');
|
|
282
|
-
el.className = 'annotation';
|
|
283
|
-
el.dataset.id = id;
|
|
284
|
-
el.style.cssText = `left:${x}px;top:${y}px;padding:4px 8px;background:#fff;border:1px solid #FF0000;border-radius:4px;color:#FF0000;font-size:14px;min-width:40px;`;
|
|
285
|
-
el.innerHTML = `<input class="label-input" value="${text}" style="color:#FF0000;font-size:14px;" />`;
|
|
286
|
-
el.querySelector('.label-input').addEventListener('input', e => {
|
|
287
|
-
const a = annotations.find(a => a.id === parseInt(el.dataset.id));
|
|
288
|
-
if (a) a.text = e.target.value;
|
|
289
|
-
});
|
|
290
|
-
el.addEventListener('mousedown', e => {
|
|
291
|
-
if (e.target.classList.contains('label-input')) return;
|
|
292
|
-
e.stopPropagation();
|
|
293
|
-
deselectAll();
|
|
294
|
-
selectedId = parseInt(el.dataset.id);
|
|
295
|
-
el.classList.add('selected');
|
|
296
|
-
const a = annotations.find(a => a.id === selectedId);
|
|
297
|
-
if (a) {
|
|
298
|
-
const rect = editor.getBoundingClientRect();
|
|
299
|
-
dragState = { type: 'move', id: selectedId, element: el, offsetX: e.clientX - rect.left - a.x, offsetY: e.clientY - rect.top - a.y };
|
|
300
|
-
}
|
|
301
|
-
});
|
|
302
|
-
return el;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
function addAnnotationFromDecoration(d) {
|
|
306
|
-
const id = nextId++;
|
|
307
|
-
if (d.type === 'rect' && d.target && 'x' in d.target) {
|
|
308
|
-
const a = { id, type: 'rect', x: d.target.x, y: d.target.y, width: d.target.width, height: d.target.height };
|
|
309
|
-
annotations.push(a);
|
|
310
|
-
editor.appendChild(createRectElement(id, a.x, a.y, a.width, a.height));
|
|
311
|
-
} else if (d.type === 'arrow' && 'x' in d.from && 'x' in d.to) {
|
|
312
|
-
const a = { id, type: 'arrow', fromX: d.from.x, fromY: d.from.y, toX: d.to.x, toY: d.to.y };
|
|
313
|
-
annotations.push(a);
|
|
314
|
-
editor.appendChild(createArrowElement(id, a.fromX, a.fromY, a.toX, a.toY));
|
|
315
|
-
} else if (d.type === 'label' && 'x' in d.position) {
|
|
316
|
-
const a = { id, type: 'label', x: d.position.x, y: d.position.y, text: d.text };
|
|
317
|
-
annotations.push(a);
|
|
318
|
-
editor.appendChild(createLabelElement(id, a.x, a.y, a.text));
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
function save() {
|
|
323
|
-
const decorations = annotations.map(a => {
|
|
324
|
-
if (a.type === 'rect') {
|
|
325
|
-
return { type: 'rect', target: { x: Math.round(a.x), y: Math.round(a.y), width: Math.round(a.width), height: Math.round(a.height) }, style: { color: '#FF0000', strokeWidth: 2 } };
|
|
326
|
-
} else if (a.type === 'arrow') {
|
|
327
|
-
return { type: 'arrow', from: { x: Math.round(a.fromX), y: Math.round(a.fromY) }, to: { x: Math.round(a.toX), y: Math.round(a.toY) }, style: { color: '#FF0000', strokeWidth: 2 } };
|
|
328
|
-
} else if (a.type === 'label') {
|
|
329
|
-
return { type: 'label', text: a.text, position: { x: Math.round(a.x), y: Math.round(a.y) }, style: { fontSize: 14, color: '#FF0000', background: '#FFFFFF' } };
|
|
330
|
-
}
|
|
331
|
-
}).filter(Boolean);
|
|
332
|
-
|
|
333
|
-
window.__SAVED_DECORATIONS__ = decorations;
|
|
334
|
-
document.title = 'SAVED';
|
|
335
|
-
}
|
|
336
|
-
</script>
|
|
337
|
-
</body>
|
|
338
|
-
</html>
|