const svg=element.querySelector('.mr-canvas'), rect=element.querySelector('.mr-box'); const clear=element.querySelector('.mr-clear'), status=element.querySelector('.mr-status'); let width=1024,height=1024,box=null,drag=null,loaded=false; const clamp=n=>Math.max(0,Math.min(1,n)); function draw() { rect.toggleAttribute('hidden',!box); if(box) { const [x1,y1,x2,y2]=box; for(const [k,v] of Object.entries({x:x1*width,y:y1*height,width:(x2-x1)*width,height:(y2-y1)*height})) rect.setAttribute(k,v); } clear.disabled=!box; status.textContent=!loaded?'元画像を読み込むと領域を選択できます。':box?'指定領域のみを編集します。領域外は元画像の画素を保持します。':'領域未指定:画像全体を編集します。'; } function publish() { props.value={box:box?[...box]:null}; } function point(e) {const r=svg.getBoundingClientRect();return [clamp((e.clientX-r.left)/r.width),clamp((e.clientY-r.top)/r.height)];} svg.addEventListener('pointerdown',e=>{ if(!loaded || !e.isPrimary || (e.pointerType==='mouse' && e.button!==0) || drag)return; e.preventDefault();drag={id:e.pointerId,start:point(e),before:box};svg.setPointerCapture(e.pointerId); }); svg.addEventListener('pointermove',e=>{ if(!drag || e.pointerId!==drag.id)return; const [x,y]=point(e),[sx,sy]=drag.start;box=[Math.min(x,sx),Math.min(y,sy),Math.max(x,sx),Math.max(y,sy)];draw(); }); svg.addEventListener('pointerup',e=>{ if(!drag || e.pointerId!==drag.id)return; const [x,y]=point(e),[sx,sy]=drag.start; if(Math.abs(x-sx)<.01 || Math.abs(y-sy)<.01) { const left=Math.max(0,Math.min(.75,sx-.125)),top=Math.max(0,Math.min(.75,sy-.125));box=[left,top,left+.25,top+.25]; } else box=[Math.min(x,sx),Math.min(y,sy),Math.max(x,sx),Math.max(y,sy)]; drag=null;if(svg.hasPointerCapture(e.pointerId))svg.releasePointerCapture(e.pointerId);draw();publish(); }); svg.addEventListener('pointercancel',()=>{if(drag)box=drag.before;drag=null;draw();}); clear.addEventListener('click',()=>{box=null;draw();publish();}); function receive() { const data=props.value; if(data?.action!=='image')return; loaded=!!data.url;width=data.width||1024;height=data.height||1024;box=null;drag=null; svg.setAttribute('viewBox',`0 0 ${width} ${height}`);svg.toggleAttribute('hidden',!loaded); element.querySelector('.mr-image').setAttribute('href',data.url||'');draw();publish(); } watch('value',receive);receive();draw();