@lhs7/wheel-selector
Version:
141 lines (140 loc) • 5.86 kB
JavaScript
import { WheelSelector } from "./WheelSelector";
import { makeCanvas, removeCanvas, drawDragging, clearCanvas, } from "../util/canvas";
export class WheelSelectorEditor extends WheelSelector {
constructor(options) {
var _a;
super(options);
this.dragginIconSize = 150;
this.draggingItem = null;
this.preItems = [];
this.mouseCanvas = null;
this.eventHandlers = {
mousedown: (event) => {
//왼쪽 클릭만 처리
if (event.button !== 0)
return;
//드래깅 대상이 존재
if (typeof this.selectedItemNo === "number") {
event.preventDefault();
//드래깅 아이템 저장
this.draggingItem = this.items[this.selectedItemNo];
//드래깅 아이템 제외 상태 저장
this.preItems = this.items.slice();
this.preItems.splice(this.selectedItemNo, 1);
} //드래깅 대상 없음
else {
this.draggingItem = null;
}
},
mousemove: (event) => {
if (this.position === null)
return;
// selector의 아이템 선택 처리
this.selectedItemNo = this.checkSelected(event.clientX, event.clientY);
this.redraw();
//캔버스 위치 조정
if (this.mouseCanvas !== null) {
const { clientX, clientY } = event;
this.mouseCanvas.style.left = `${clientX - this.dragginIconSize / 2}px`;
this.mouseCanvas.style.top = `${clientY - this.dragginIconSize / 2}px`;
}
//드래깅 상태이며, 선택 영역에 있을경우 경우 드래깅 아이콘 그리기
if (this.draggingItem !== null &&
typeof this.selectedItemNo !== "number") {
drawDragging(this);
}
else {
clearCanvas(this.mouseCanvas);
}
},
mouseup: (event) => {
//왼쪽 클릭후 드래깅 상태가 있는 경우만 처리
if (event.button !== 0 || this.draggingItem === null)
return;
event.preventDefault();
this.draggingItem = null;
//마우스 아이콘 삭제
clearCanvas(this.mouseCanvas);
//아이템 변경 업데이트
this.onUpdated(this.items);
},
};
this.onUpdated = (_a = options.onUpdated) !== null && _a !== void 0 ? _a : (() => { });
this.calculate_Size_Pos(options.baseElement);
this.addEventHandlers();
}
calculate_Size_Pos(baseElement) {
if (baseElement === null)
return;
const { width, height, top, left } = baseElement.getBoundingClientRect();
const centerX = left + width / 2;
const centerY = top + height / 2;
this.outerDistance = Math.min(width, height) / 2;
this.innerDistance = this.outerDistance / 2;
this.activateSelector({ x: centerX, y: centerY });
}
checkSelected(ex, ey) {
const { angle, length } = ((ex, ey) => {
const { x, y } = this.position;
const [dx, dy] = [ex - x, ey - y];
const angle = Math.atan2(dy, dx);
const length = Math.sqrt(dy * dy + dx * dx);
return {
angle,
length,
};
})(ex, ey);
//드래그 상태이면 이전 상태로 덮어씌우고 시작
if (this.draggingItem !== null)
this.items = this.preItems.slice();
//if (length < this.innerDistance) return "CANCEL";
if (length > this.outerDistance)
return null;
const normalizedAngle = ((angle % (2 * Math.PI)) + 2 * Math.PI) % (2 * Math.PI);
let startAngle = 0;
// 드래깅 아이템이 존재할 경우 아이템 수 + 1
const itemLength = this.items.length + (this.draggingItem === null ? 0 : 1);
const angleStep = (2 * Math.PI) / itemLength;
let selectedIdx = null;
for (let idx = 0; idx < itemLength; idx++) {
const endAngle = startAngle + angleStep;
if (normalizedAngle >= startAngle && normalizedAngle < endAngle) {
selectedIdx = idx;
break;
}
startAngle = endAngle;
}
if (typeof selectedIdx === "number" && this.draggingItem !== null) {
//선택된 아이템이 존재하면 드래깅 아이템을 해당 위치에 삽입
this.items.splice(selectedIdx, 0, this.draggingItem);
}
return selectedIdx;
}
activateSelector(pos) {
if (this.mouseCanvas !== null)
removeCanvas(this.mouseCanvas);
this.mouseCanvas = makeCanvas({ x: 0, y: 0 }, this.dragginIconSize);
this.mouseCanvas.style.zIndex = "10001";
super.activateSelector(pos);
}
deactivateSelector() {
if (this.mouseCanvas !== null)
removeCanvas(this.mouseCanvas);
super.deactivateSelector();
}
addEventHandlers() {
if (document === null)
return;
for (const [event, handler] of Object.entries(this.eventHandlers)) {
document.addEventListener(event, handler, true);
}
}
removeEventHandlers() {
if (document === null)
return;
removeCanvas(this.mouseCanvas);
for (const [event, handler] of Object.entries(this.eventHandlers)) {
document.removeEventListener(event, handler, true);
}
}
}