Files
sam-kd/guiderail/js/drawingTool.js
hskwon aca1767eb9 초기 커밋: 5130 레거시 시스템
- URL 하드코딩 → .env APP_URL 기반 동적 URL로 변경
- DB 연결 하드코딩 → .env 기반으로 변경
- MySQL strict mode DATE 오류 수정
2025-12-10 20:14:31 +09:00

274 lines
11 KiB
JavaScript

// drawingTool.js
;(function($){
var DrawingTool = {
$canvas: null,
ctx: null,
drawMode: 'polyline',
drawColor: '#000000',
eraserWidth: 10,
isRightAngle: true,
polylinePoints: [],
isDrawing: false,
lastX: 0,
lastY: 0,
originalImage: null,
init: function(){
this.bindDrawBtn();
},
bindDrawBtn: function(){
var self = this;
$('#drawBtn')
.off('click.drawingTool')
.on('click.drawingTool', function(){
var active = !$(this).hasClass('active');
$(this).toggleClass('active', active).text(active ? '그리기 중지' : '그리기');
if(active) self.createUI();
else self.destroyUI();
});
},
createUI: function(){
var self = this;
$('.drawing-tools-container').remove();
var html =
'<div class="drawing-tools-container mb-3">'+
' <div class="card">'+
' <div class="card-header"><h6 class="mb-0">그리기 도구</h6></div>'+
' <div class="card-body row">'+
' <div class="col-md-8">'+
' <canvas id="drawingCanvas" style="border:1px solid #ccc; cursor:crosshair; width:100%;"></canvas>'+
' </div>'+
' <div class="col-md-4">'+
' <div class="mb-3">'+
' <label>모드:</label>'+
' <select id="drawMode" class="form-select">'+
' <option value="polyline">폴리라인</option>'+
' <option value="free">자유선</option>'+
' <option value="eraser">지우개</option>'+
' <option value="text">텍스트</option>'+
' </select>'+
' </div>'+
' <div class="form-check mb-3">'+
' <input id="rightAngleCheck" class="form-check-input" type="checkbox" checked>'+
' <label class="form-check-label" for="rightAngleCheck">직각 그리기</label>'+
' </div>'+
' <div class="mb-3">'+
' <label>색상:</label>'+
' <input id="drawColor" class="form-control" type="color" value="'+this.drawColor+'">'+
' </div>'+
' <div class="mb-3 eraser-control">'+
' <label>지우개 굵기:</label>'+
' <input id="eraserWidth" class="form-control-range" type="range" min="2" max="50" value="'+this.eraserWidth+'">'+
' <small id="eraserWidthLabel" class="text-muted">'+this.eraserWidth+'px</small>'+
' </div>'+
' <div class="mb-3">'+
' <button type="button" id="clearBtn" class="btn btn-outline-secondary btn-sm">초기화</button>'+
' </div>'+
' </div>'+
' </div>'+
' </div>'+
'</div>';
var $target = $('#materialSummaryArea').length ? $('#materialSummaryArea') : $('#myModal .modal-body');
$target.prepend(html);
this.$canvas = $('#drawingCanvas').attr({width:600, height:400});
this.ctx = this.$canvas[0].getContext('2d');
this.loadImage();
this.bindControls();
this.bindCanvas();
},
destroyUI: function(){
$('.drawing-tools-container').remove();
this.polylinePoints = [];
this.isDrawing = false;
this.drawMode = 'polyline';
this.eraserWidth = 10;
this.drawColor = '#000000';
$(document).off('.drawingTool');
},
loadImage: function(){
var src = $('#previewContainer img').attr('src');
if(src){
var img = new Image(), self=this;
img.crossOrigin='anonymous';
img.onload = function(){
self.$canvas.attr({width:img.width,height:img.height});
self.ctx.drawImage(img,0,0);
self.originalImage = img;
};
img.onerror = function(){ self.clearCanvas(); };
img.src = src;
} else this.clearCanvas();
},
clearCanvas: function(){
this.clearCanvasBackground();
if(this.originalImage) this.ctx.drawImage(this.originalImage,0,0);
this.polylinePoints=[];
},
bindControls: function(){
var self=this;
var $cont=$('.drawing-tools-container');
$cont.find('#drawMode').off('change.drawingTool').on('change.drawingTool',function(){
self.drawMode = this.value;
self.polylinePoints = [];
self.clearCanvas();
$cont.find('.eraser-control').toggle(self.drawMode==='eraser');
});
$cont.find('#rightAngleCheck').off('change.drawingTool').on('change.drawingTool',function(){
self.isRightAngle = this.checked;
});
$cont.find('#drawColor').off('change.drawingTool').on('change.drawingTool',function(){
self.drawColor = this.value;
});
$cont.find('#eraserWidth').off('input.drawingTool').on('input.drawingTool',function(){
var v = parseInt(this.value,10);
if(!isNaN(v)){
self.eraserWidth = v;
$cont.find('#eraserWidthLabel').text(v+'px');
}
});
$cont.find('#clearBtn').off('click.drawingTool').on('click.drawingTool',function(){
self.clearCanvas();
});
$(document).off('keydown.drawingTool').on('keydown.drawingTool',function(e){
if(e.key==='Escape' && self.drawMode==='polyline' && self.polylinePoints.length){
self.polylinePoints=[];
self.clearCanvas();
}
});
},
bindCanvas: function(){
var self=this, $c=this.$canvas;
$c.off('.drawingTool')
.on('mousedown.drawingTool', function(e){
var off=$c.offset(), x=e.pageX-off.left, y=e.pageY-off.top;
if(self.drawMode==='free'||self.drawMode==='eraser'){
self.isDrawing=true; self.lastX=x; self.lastY=y;
}
})
.on('mousemove.drawingTool', function(e){
var off=$c.offset(), x=e.pageX-off.left, y=e.pageY-off.top;
if(self.drawMode==='polyline' && self.polylinePoints.length){
self.clearCanvas(); if(self.originalImage) self.ctx.drawImage(self.originalImage,0,0);
self.drawPolylines();
var prev=self.polylinePoints.slice(-1)[0];
if(prev){
var dx=Math.abs(x-prev.x), dy=Math.abs(y-prev.y);
var endX=self.isRightAngle?(dx>dy?x:prev.x):x;
var endY=self.isRightAngle?(dx>dy?prev.y:y):y;
self.ctx.setLineDash([5,5]);
self.ctx.strokeStyle='#888'; self.ctx.lineWidth=1;
self.ctx.beginPath(); self.ctx.moveTo(prev.x,prev.y); self.ctx.lineTo(endX,endY); self.ctx.stroke();
self.ctx.setLineDash([]);
}
}
if(self.isDrawing){
self.ctx.globalCompositeOperation=self.drawMode==='eraser'?'destination-out':'source-over';
self.ctx.strokeStyle=self.drawMode==='eraser'?null:self.drawColor;
self.ctx.lineWidth=self.drawMode==='eraser'?self.eraserWidth:2;
self.ctx.lineCap='round';
self.ctx.beginPath(); self.ctx.moveTo(self.lastX,self.lastY); self.ctx.lineTo(x,y); self.ctx.stroke();
self.lastX=x; self.lastY=y;
}
})
.on('mouseup.drawingTool mouseleave.drawingTool', function(e){
if(self.drawMode==='polyline'){
var off=$c.offset(), x=e.pageX-off.left, y=e.pageY-off.top;
if(!self.isDrawing){
if(self.polylinePoints.length===0) self.polylinePoints.push({x:x,y:y});
else{
var prev=self.polylinePoints.slice(-1)[0];
if(prev){
var dx=Math.abs(x-prev.x), dy=Math.abs(y-prev.y);
var endX=self.isRightAngle?(dx>dy?x:prev.x):x;
var endY=self.isRightAngle?(dx>dy?prev.y:y):y;
self.polylinePoints.push({x:endX,y:endY});
self.clearCanvas(); if(self.originalImage) self.ctx.drawImage(self.originalImage,0,0);
self.drawPolylines();
}
}
}
}
self.isDrawing=false;
})
.on('click.drawingTool', function(e){
if(self.drawMode==='text'){
var off=$c.offset(), x=e.pageX-off.left, y=e.pageY-off.top;
var $input=$('<input type="text" maxlength="100">').css({position:'absolute',left:off.left+x+'px',top:off.top+y+'px',fontSize:'14px',zIndex:9999}).appendTo('body').focus();
$input.on('keydown',function(evt){if(evt.key==='Enter'){var t=$input.val();if(t){self.ctx.fillStyle=self.drawColor;self.ctx.font='14px Arial';self.ctx.fillText(t,x,y+14);} $input.remove();}else if(evt.key==='Escape')$input.remove();}).on('blur',function(){$input.remove();});
}
});
},
drawPolylines: function(){
if(!this.polylinePoints.length) return;
this.ctx.setLineDash([]);
this.ctx.strokeStyle=this.drawColor;
this.ctx.lineWidth=2;
this.ctx.beginPath();
this.ctx.moveTo(this.polylinePoints[0].x,this.polylinePoints[0].y);
for(var i=1;i<this.polylinePoints.length;i++){
this.ctx.lineTo(this.polylinePoints[i].x,this.polylinePoints[i].y);
}
this.ctx.stroke();
},
redrawCanvas: function(){
this.clearCanvasBackground();
if (this.originalImage) this.ctx.drawImage(this.originalImage,0,0);
},
clearCanvasBackground: function(){
if (this.ctx && this.$canvas) {
this.ctx.clearRect(0, 0, this.$canvas[0].width, this.$canvas[0].height);
}
},
cleanup: function(){
$('.drawing-tools-container').remove();
this.polylinePoints=[];
this.isDrawing=false;
this.drawMode='polyline';
this.lineWidth=2;
this.drawColor='#000000';
this.isRightAngle=true;
this.originalImage=null;
}
};
// 외부 참조용 글로벌 변수로 노출
window.DrawingTool = DrawingTool;
// 문서 로드 시와, 부트스트랩 모달이 뜰 때마다 init 호출
$(function(){
console.log('DOM ready → DrawingTool.init()');
DrawingTool.init();
// 만약 Bootstrap modal 을 쓰신다면
$('#myModal').on('shown.bs.modal', function(){
console.log('modal opened → DrawingTool.init()');
DrawingTool.init();
});
});
})(jQuery);