修改
This commit is contained in:
+30
-1
@@ -237,6 +237,31 @@ body {
|
|||||||
box-shadow: inset 0 -2px 0 var(--stop);
|
box-shadow: inset 0 -2px 0 var(--stop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mode-btn.has-marker::after {
|
||||||
|
content: "●";
|
||||||
|
margin-left: 4px;
|
||||||
|
font-size: 0.55rem;
|
||||||
|
vertical-align: super;
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mode-btn[data-mode="entry"].has-marker::after {
|
||||||
|
color: var(--entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mode-btn[data-mode="exit"].has-marker::after {
|
||||||
|
color: var(--exit);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mode-btn[data-mode="stop"].has-marker::after {
|
||||||
|
color: var(--stop);
|
||||||
|
}
|
||||||
|
|
||||||
|
.viewport.is-panning,
|
||||||
|
.viewport.is-panning #overlay-canvas {
|
||||||
|
cursor: grabbing;
|
||||||
|
}
|
||||||
|
|
||||||
.workspace {
|
.workspace {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -325,7 +350,11 @@ body {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
cursor: crosshair;
|
cursor: grab;
|
||||||
|
}
|
||||||
|
|
||||||
|
#overlay-canvas.can-pan {
|
||||||
|
cursor: grab;
|
||||||
}
|
}
|
||||||
|
|
||||||
#overlay-canvas.can-drag {
|
#overlay-canvas.can-drag {
|
||||||
|
|||||||
+2
-2
@@ -15,7 +15,7 @@
|
|||||||
<input type="file" id="file-input" accept="image/jpeg,image/png,.jpg,.jpeg,.png" hidden>
|
<input type="file" id="file-input" accept="image/jpeg,image/png,.jpg,.jpeg,.png" hidden>
|
||||||
</label>
|
</label>
|
||||||
<div class="mode-group" role="group" aria-label="标注模式">
|
<div class="mode-group" role="group" aria-label="标注模式">
|
||||||
<button type="button" class="btn mode-btn active" data-mode="entry">入场</button>
|
<button type="button" class="btn mode-btn" data-mode="entry">入场</button>
|
||||||
<button type="button" class="btn mode-btn" data-mode="exit">出场</button>
|
<button type="button" class="btn mode-btn" data-mode="exit">出场</button>
|
||||||
<button type="button" class="btn mode-btn" data-mode="stop">止损</button>
|
<button type="button" class="btn mode-btn" data-mode="stop">止损</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
<span>入场 <i class="legend entry"></i></span>
|
<span>入场 <i class="legend entry"></i></span>
|
||||||
<span>出场 <i class="legend exit"></i></span>
|
<span>出场 <i class="legend exit"></i></span>
|
||||||
<span>止损 <i class="legend stop"></i></span>
|
<span>止损 <i class="legend stop"></i></span>
|
||||||
<span class="footer-note">滚轮缩放 · 右键拖动画布 · 方向面板/滑块设置箭头朝向</span>
|
<span class="footer-note">空白处拖动平移 · 选中类型后单击放置(各仅一个)</span>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<script src="js/app.js"></script>
|
<script src="js/app.js"></script>
|
||||||
|
|||||||
+159
-74
@@ -40,22 +40,25 @@
|
|||||||
const angleSlider = document.getElementById("angle-slider");
|
const angleSlider = document.getElementById("angle-slider");
|
||||||
const angleInput = document.getElementById("angle-input");
|
const angleInput = document.getElementById("angle-input");
|
||||||
|
|
||||||
let currentMode = "entry";
|
let currentMode = null;
|
||||||
let pendingAngle = 0;
|
let pendingAngle = 0;
|
||||||
let markers = [];
|
let markers = [];
|
||||||
let baseWidth = 0;
|
let baseWidth = 0;
|
||||||
let baseHeight = 0;
|
let baseHeight = 0;
|
||||||
let zoom = 1;
|
let zoom = 1;
|
||||||
let imageLoaded = false;
|
let imageLoaded = false;
|
||||||
|
let uploadedFileName = "";
|
||||||
let dragIndex = -1;
|
let dragIndex = -1;
|
||||||
let selectedIndex = -1;
|
let selectedIndex = -1;
|
||||||
let isDragging = false;
|
let isDraggingMarker = false;
|
||||||
let didDragMove = false;
|
let didDragMove = false;
|
||||||
let isPanning = false;
|
let isPanning = false;
|
||||||
|
let didPanMove = false;
|
||||||
let panStartX = 0;
|
let panStartX = 0;
|
||||||
let panStartY = 0;
|
let panStartY = 0;
|
||||||
let panScrollLeft = 0;
|
let panScrollLeft = 0;
|
||||||
let panScrollTop = 0;
|
let panScrollTop = 0;
|
||||||
|
const PAN_THRESHOLD = 4;
|
||||||
|
|
||||||
function setHint(text) {
|
function setHint(text) {
|
||||||
statusHint.textContent = text;
|
statusHint.textContent = text;
|
||||||
@@ -121,6 +124,60 @@
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function findMarkerIndexByType(type) {
|
||||||
|
return markers.findIndex(function (m) {
|
||||||
|
return m.type === type;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateModeButtonStates() {
|
||||||
|
modeButtons.forEach(function (btn) {
|
||||||
|
const type = btn.dataset.mode;
|
||||||
|
btn.classList.toggle("has-marker", findMarkerIndexByType(type) >= 0);
|
||||||
|
btn.classList.toggle("active", currentMode === type);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearModeSelection() {
|
||||||
|
currentMode = null;
|
||||||
|
updateModeButtonStates();
|
||||||
|
}
|
||||||
|
|
||||||
|
function setMode(mode) {
|
||||||
|
if (currentMode === mode) {
|
||||||
|
clearModeSelection();
|
||||||
|
setHint("已取消选择 · 拖动空白处平移画布 · 点击入场/出场/止损开始标注");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentMode = mode;
|
||||||
|
const info = MARKER_TYPES[mode];
|
||||||
|
const existIdx = findMarkerIndexByType(mode);
|
||||||
|
|
||||||
|
if (existIdx >= 0) {
|
||||||
|
selectedIndex = existIdx;
|
||||||
|
syncAngleUI(markers[existIdx].angle);
|
||||||
|
setHint(
|
||||||
|
info.label +
|
||||||
|
" 已标注 · 单击图上可移动位置,或拖动箭头 · 再次点击「" +
|
||||||
|
info.label +
|
||||||
|
"」取消选择"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
selectedIndex = -1;
|
||||||
|
setHint(
|
||||||
|
"已选择「" +
|
||||||
|
info.label +
|
||||||
|
"」· 在图上单击放置(仅一个)· 方向 " +
|
||||||
|
pendingAngle +
|
||||||
|
"°"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateModeButtonStates();
|
||||||
|
redraw();
|
||||||
|
}
|
||||||
|
|
||||||
function drawArrowMarker(targetCtx, x, y, angleDeg, color, highlight) {
|
function drawArrowMarker(targetCtx, x, y, angleDeg, color, highlight) {
|
||||||
const w = ARROW_WIDTH;
|
const w = ARROW_WIDTH;
|
||||||
const h = ARROW_HEAD;
|
const h = ARROW_HEAD;
|
||||||
@@ -268,8 +325,14 @@
|
|||||||
selectedIndex = index;
|
selectedIndex = index;
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
syncAngleUI(markers[index].angle);
|
syncAngleUI(markers[index].angle);
|
||||||
|
const label = MARKER_TYPES[markers[index].type].label;
|
||||||
setHint(
|
setHint(
|
||||||
"已选中标记,可调整方向或拖拽移动;点击空白处添加新标记"
|
"已选中「" +
|
||||||
|
label +
|
||||||
|
"」· 可拖动移动或调整方向" +
|
||||||
|
(currentMode
|
||||||
|
? ""
|
||||||
|
: " · 点击对应类型按钮后可重新放置")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
redraw();
|
redraw();
|
||||||
@@ -279,8 +342,10 @@
|
|||||||
markers = [];
|
markers = [];
|
||||||
dragIndex = -1;
|
dragIndex = -1;
|
||||||
selectedIndex = -1;
|
selectedIndex = -1;
|
||||||
isDragging = false;
|
isDraggingMarker = false;
|
||||||
didDragMove = false;
|
didDragMove = false;
|
||||||
|
didPanMove = false;
|
||||||
|
clearModeSelection();
|
||||||
redraw();
|
redraw();
|
||||||
updateButtons();
|
updateButtons();
|
||||||
}
|
}
|
||||||
@@ -292,6 +357,16 @@
|
|||||||
directionRow.hidden = !show;
|
directionRow.hidden = !show;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getDownloadFileName() {
|
||||||
|
if (!uploadedFileName) {
|
||||||
|
return "标注1.png";
|
||||||
|
}
|
||||||
|
const lastDot = uploadedFileName.lastIndexOf(".");
|
||||||
|
const base =
|
||||||
|
lastDot > 0 ? uploadedFileName.slice(0, lastDot) : uploadedFileName;
|
||||||
|
return base + "1.png";
|
||||||
|
}
|
||||||
|
|
||||||
function loadImageFile(file) {
|
function loadImageFile(file) {
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
const validTypes = ["image/jpeg", "image/png"];
|
const validTypes = ["image/jpeg", "image/png"];
|
||||||
@@ -302,6 +377,8 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uploadedFileName = file.name;
|
||||||
|
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.onload = function (e) {
|
reader.onload = function (e) {
|
||||||
chartImage.onload = function () {
|
chartImage.onload = function () {
|
||||||
@@ -310,6 +387,7 @@
|
|||||||
dropZone.classList.remove("drag-over");
|
dropZone.classList.remove("drag-over");
|
||||||
zoom = 1;
|
zoom = 1;
|
||||||
clearAnnotations();
|
clearAnnotations();
|
||||||
|
clearModeSelection();
|
||||||
syncAngleUI(0);
|
syncAngleUI(0);
|
||||||
requestAnimationFrame(function () {
|
requestAnimationFrame(function () {
|
||||||
calculateBaseSize();
|
calculateBaseSize();
|
||||||
@@ -317,9 +395,7 @@
|
|||||||
viewport.scrollLeft = 0;
|
viewport.scrollLeft = 0;
|
||||||
viewport.scrollTop = 0;
|
viewport.scrollTop = 0;
|
||||||
setHint(
|
setHint(
|
||||||
"滚轮缩放 · 右键/中键拖动画布 · 设置方向后单击添加 " +
|
"滚轮缩放 · 拖动空白处平移 · 先点「入场/出场/止损」再单击图上放置(各仅一个)"
|
||||||
MARKER_TYPES[currentMode].label +
|
|
||||||
" 标记"
|
|
||||||
);
|
);
|
||||||
updateButtons();
|
updateButtons();
|
||||||
});
|
});
|
||||||
@@ -338,29 +414,35 @@
|
|||||||
reader.readAsDataURL(file);
|
reader.readAsDataURL(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addMarker(x, y) {
|
function placeOrMoveMarker(x, y) {
|
||||||
|
if (!currentMode) return;
|
||||||
|
|
||||||
const type = currentMode;
|
const type = currentMode;
|
||||||
const info = MARKER_TYPES[type];
|
const info = MARKER_TYPES[type];
|
||||||
const ratio = xyToRatio(x, y);
|
const ratio = xyToRatio(x, y);
|
||||||
markers.push({
|
const existIdx = findMarkerIndexByType(type);
|
||||||
xRatio: ratio.xRatio,
|
|
||||||
yRatio: ratio.yRatio,
|
if (existIdx >= 0) {
|
||||||
type: type,
|
markers[existIdx].xRatio = ratio.xRatio;
|
||||||
color: info.color,
|
markers[existIdx].yRatio = ratio.yRatio;
|
||||||
angle: pendingAngle,
|
markers[existIdx].angle = pendingAngle;
|
||||||
});
|
selectedIndex = existIdx;
|
||||||
selectedIndex = markers.length - 1;
|
setHint(info.label + " 已移动到当前位置(" + pendingAngle + "°)");
|
||||||
|
} else {
|
||||||
|
markers.push({
|
||||||
|
xRatio: ratio.xRatio,
|
||||||
|
yRatio: ratio.yRatio,
|
||||||
|
type: type,
|
||||||
|
color: info.color,
|
||||||
|
angle: pendingAngle,
|
||||||
|
});
|
||||||
|
selectedIndex = markers.length - 1;
|
||||||
|
setHint("已放置「" + info.label + "」(" + pendingAngle + "°)");
|
||||||
|
}
|
||||||
|
|
||||||
redraw();
|
redraw();
|
||||||
updateButtons();
|
updateButtons();
|
||||||
setHint(
|
updateModeButtonStates();
|
||||||
"已添加 " +
|
|
||||||
info.label +
|
|
||||||
"(" +
|
|
||||||
pendingAngle +
|
|
||||||
"°,共 " +
|
|
||||||
markers.length +
|
|
||||||
" 个)"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function exportImage() {
|
function exportImage() {
|
||||||
@@ -394,18 +476,7 @@
|
|||||||
}
|
}
|
||||||
const url = URL.createObjectURL(blob);
|
const url = URL.createObjectURL(blob);
|
||||||
const a = document.createElement("a");
|
const a = document.createElement("a");
|
||||||
const ts = new Date();
|
const name = getDownloadFileName();
|
||||||
const pad = (n) => String(n).padStart(2, "0");
|
|
||||||
const name =
|
|
||||||
"kline-label-" +
|
|
||||||
ts.getFullYear() +
|
|
||||||
pad(ts.getMonth() + 1) +
|
|
||||||
pad(ts.getDate()) +
|
|
||||||
"-" +
|
|
||||||
pad(ts.getHours()) +
|
|
||||||
pad(ts.getMinutes()) +
|
|
||||||
pad(ts.getSeconds()) +
|
|
||||||
".png";
|
|
||||||
a.href = url;
|
a.href = url;
|
||||||
a.download = name;
|
a.download = name;
|
||||||
document.body.appendChild(a);
|
document.body.appendChild(a);
|
||||||
@@ -417,33 +488,28 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateCursor(x, y) {
|
function updateCursor(x, y) {
|
||||||
if (isPanning) return;
|
if (isPanning) {
|
||||||
|
canvas.classList.remove("can-drag");
|
||||||
|
canvas.classList.add("can-pan");
|
||||||
|
return;
|
||||||
|
}
|
||||||
const idx = findMarkerAt(x, y);
|
const idx = findMarkerAt(x, y);
|
||||||
|
canvas.classList.remove("can-pan");
|
||||||
if (idx >= 0) {
|
if (idx >= 0) {
|
||||||
canvas.classList.add("can-drag");
|
canvas.classList.add("can-drag");
|
||||||
} else {
|
} else {
|
||||||
canvas.classList.remove("can-drag");
|
canvas.classList.remove("can-drag");
|
||||||
|
canvas.classList.add("can-pan");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
modeButtons.forEach(function (btn) {
|
modeButtons.forEach(function (btn) {
|
||||||
btn.addEventListener("click", function (e) {
|
btn.addEventListener("click", function (e) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
modeButtons.forEach(function (b) {
|
|
||||||
b.classList.remove("active");
|
|
||||||
});
|
|
||||||
btn.classList.add("active");
|
|
||||||
currentMode = btn.dataset.mode;
|
|
||||||
didDragMove = false;
|
didDragMove = false;
|
||||||
if (imageLoaded) {
|
didPanMove = false;
|
||||||
setHint(
|
if (!imageLoaded) return;
|
||||||
"当前:" +
|
setMode(btn.dataset.mode);
|
||||||
MARKER_TYPES[currentMode].label +
|
|
||||||
" · 方向 " +
|
|
||||||
pendingAngle +
|
|
||||||
"° · 单击添加标记"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -519,6 +585,7 @@
|
|||||||
function startPan(e) {
|
function startPan(e) {
|
||||||
if (!imageLoaded) return;
|
if (!imageLoaded) return;
|
||||||
isPanning = true;
|
isPanning = true;
|
||||||
|
didPanMove = false;
|
||||||
panStartX = e.clientX;
|
panStartX = e.clientX;
|
||||||
panStartY = e.clientY;
|
panStartY = e.clientY;
|
||||||
panScrollLeft = viewport.scrollLeft;
|
panScrollLeft = viewport.scrollLeft;
|
||||||
@@ -537,31 +604,41 @@
|
|||||||
|
|
||||||
if (e.button !== 0) return;
|
if (e.button !== 0) return;
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
didDragMove = false;
|
||||||
|
didPanMove = false;
|
||||||
|
|
||||||
const pt = getCanvasPoint(e);
|
const pt = getCanvasPoint(e);
|
||||||
const idx = findMarkerAt(pt.x, pt.y);
|
const idx = findMarkerAt(pt.x, pt.y);
|
||||||
|
|
||||||
if (idx >= 0) {
|
if (idx >= 0) {
|
||||||
dragIndex = idx;
|
dragIndex = idx;
|
||||||
isDragging = true;
|
isDraggingMarker = true;
|
||||||
didDragMove = false;
|
|
||||||
selectMarker(idx);
|
selectMarker(idx);
|
||||||
canvas.classList.add("can-drag");
|
canvas.classList.add("can-drag");
|
||||||
} else {
|
return;
|
||||||
selectMarker(-1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
selectMarker(-1);
|
||||||
|
startPan(e);
|
||||||
});
|
});
|
||||||
|
|
||||||
canvas.addEventListener("mousemove", function (e) {
|
canvas.addEventListener("mousemove", function (e) {
|
||||||
if (!imageLoaded) return;
|
if (!imageLoaded) return;
|
||||||
|
|
||||||
if (isPanning) {
|
if (isPanning) {
|
||||||
viewport.scrollLeft = panScrollLeft - (e.clientX - panStartX);
|
const dx = e.clientX - panStartX;
|
||||||
viewport.scrollTop = panScrollTop - (e.clientY - panStartY);
|
const dy = e.clientY - panStartY;
|
||||||
|
if (Math.abs(dx) > PAN_THRESHOLD || Math.abs(dy) > PAN_THRESHOLD) {
|
||||||
|
didPanMove = true;
|
||||||
|
}
|
||||||
|
viewport.scrollLeft = panScrollLeft - dx;
|
||||||
|
viewport.scrollTop = panScrollTop - dy;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const pt = getCanvasPoint(e);
|
const pt = getCanvasPoint(e);
|
||||||
|
|
||||||
if (isDragging && dragIndex >= 0) {
|
if (isDraggingMarker && dragIndex >= 0) {
|
||||||
didDragMove = true;
|
didDragMove = true;
|
||||||
const ratio = xyToRatio(
|
const ratio = xyToRatio(
|
||||||
Math.max(0, Math.min(canvas.width, pt.x)),
|
Math.max(0, Math.min(canvas.width, pt.x)),
|
||||||
@@ -581,19 +658,20 @@
|
|||||||
viewport.classList.remove("is-panning");
|
viewport.classList.remove("is-panning");
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas.addEventListener("mouseup", function (e) {
|
function endPointer() {
|
||||||
if (e.button === 1 || e.button === 2 || isPanning) {
|
endPan();
|
||||||
endPan();
|
isDraggingMarker = false;
|
||||||
}
|
|
||||||
isDragging = false;
|
|
||||||
dragIndex = -1;
|
dragIndex = -1;
|
||||||
|
canvas.classList.remove("can-drag", "can-pan");
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas.addEventListener("mouseup", function () {
|
||||||
|
endPointer();
|
||||||
});
|
});
|
||||||
|
|
||||||
canvas.addEventListener("mouseleave", function () {
|
canvas.addEventListener("mouseleave", function () {
|
||||||
endPan();
|
endPointer();
|
||||||
isDragging = false;
|
canvas.classList.remove("can-pan");
|
||||||
dragIndex = -1;
|
|
||||||
canvas.classList.remove("can-drag");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
canvas.addEventListener("contextmenu", function (e) {
|
canvas.addEventListener("contextmenu", function (e) {
|
||||||
@@ -602,26 +680,32 @@
|
|||||||
|
|
||||||
canvas.addEventListener("click", function (e) {
|
canvas.addEventListener("click", function (e) {
|
||||||
if (!imageLoaded) return;
|
if (!imageLoaded) return;
|
||||||
if (didDragMove) {
|
if (didDragMove || didPanMove) {
|
||||||
didDragMove = false;
|
didDragMove = false;
|
||||||
|
didPanMove = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!currentMode) return;
|
||||||
|
|
||||||
const pt = getCanvasPoint(e);
|
const pt = getCanvasPoint(e);
|
||||||
if (findMarkerAt(pt.x, pt.y) >= 0) return;
|
if (findMarkerAt(pt.x, pt.y) >= 0) return;
|
||||||
addMarker(pt.x, pt.y);
|
placeOrMoveMarker(pt.x, pt.y);
|
||||||
});
|
});
|
||||||
|
|
||||||
btnUndo.addEventListener("click", function () {
|
btnUndo.addEventListener("click", function () {
|
||||||
if (markers.length === 0) return;
|
if (markers.length === 0) return;
|
||||||
markers.pop();
|
const removed = markers.pop();
|
||||||
if (selectedIndex >= markers.length) {
|
if (currentMode === removed.type) {
|
||||||
|
selectedIndex = -1;
|
||||||
|
} else if (selectedIndex >= markers.length) {
|
||||||
selectedIndex = markers.length - 1;
|
selectedIndex = markers.length - 1;
|
||||||
}
|
}
|
||||||
redraw();
|
redraw();
|
||||||
updateButtons();
|
updateButtons();
|
||||||
|
updateModeButtonStates();
|
||||||
setHint(
|
setHint(
|
||||||
markers.length
|
markers.length
|
||||||
? "已撤销最后一个标记,剩余 " + markers.length + " 个"
|
? "已撤销「" + MARKER_TYPES[removed.type].label + "」"
|
||||||
: "已撤销全部标记"
|
: "已撤销全部标记"
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -641,9 +725,10 @@
|
|||||||
applyLayout();
|
applyLayout();
|
||||||
});
|
});
|
||||||
|
|
||||||
window.addEventListener("mouseup", endPan);
|
window.addEventListener("mouseup", endPointer);
|
||||||
|
|
||||||
showEditorUI(false);
|
showEditorUI(false);
|
||||||
updateButtons();
|
updateButtons();
|
||||||
|
updateModeButtonStates();
|
||||||
syncAngleUI(0);
|
syncAngleUI(0);
|
||||||
})();
|
})();
|
||||||
|
|||||||
Reference in New Issue
Block a user