JQ drag + rotate + multipoint zoom

Time:2020-10-29

<!DOCTYPE html>
<html lang=”en”>
<head>

<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript"></script>
<style>
    *{
        margin: 0;
        padding: 0;
        box-sizing: border-box;
    }
    #box{
        width: 1280px;
        height: 720px;
        position: absolute;
        top: 50%;
        left: 50%;
        margin-top: -360px;
        margin-left: -640px;
        box-shadow: 0 0 10px rgba(0,0,0,.5);
    }
    #boxInner{
        width: 100%;
        height: 100%;
        position: relative;
    }
    #divBox{
        width: 200px;
        height: 200px;
        position: absolute;
        top: 64px;
        left: 128px;
        background-color: olivedrab;
    }
    .inner{
        width: 100%;
        height: 100%;
        position: relative;
    }
    .bot{
        width: 14px;
        height: 14px;
        background-color: red;
        position: absolute;
    }
    .bot1{
        left: -14px;
        top: -14px;
    }
    .bot2{
        left: 50%;
        margin-left: -7px;
        top: -14px;
    }
    .bot3{
        top: -14px;
        right: -14px;
    }
    .bot4{
        top: 50%;
        margin-top: -7px;
        left: -14px;
    }
    .bot5{
        top: 50%;
        margin-top: -7px;
        right: -14px;
    }
    .bot6{
        left: -14px;
        bottom: -14px;
    }
    .bot7{
        left: 50%;
        margin-left: -7px;
        bottom: -14px;
    }
    .bot8{
        right: -14px;
        bottom: -14px;
    }
    .rotate{
        width: 14px;
        height: 14px;
        background-color: black;
        position: absolute;
        top: 50%;
        margin-top: -7px;
        right: -30px;
    }
</style>

</head>
<body>

<div id="box"> 
    <div id="boxInner">
        <div id="divBox">
            <div class="inner">
                <div id="tl" class="bot bot1"></div>
                <div id="tm" class="bot bot2"></div>
                <div id="tr" class="bot bot3"></div>
                <div id="ml" class="bot bot4"></div>
                <div id="mr" class="bot bot5"></div>
                <div id="bl" class="bot bot6"></div>
                <div id="bm" class="bot bot7"></div>
                <div id="br" class="bot bot8"></div>
                <div class="rotate"></div>
            </div>
        </div>
    </div>
</div>
<script>
$(function(){
    $('#divBox').on('mousedown',function(e){
        e.stopPropagation();
        e.preventDefault()
        $(this).css('cursor','move');
        let isMove = true;
        let x = e.clientX;
        let y = e.clientY;

        let l = parseInt($(this).css('left'));
        let t = parseInt($(this).css('top'));
        let moveEvent = null;
        $('#box').on('mousemove',function(ev){
            moveEvent = ev;
            if(!isMove){
                return
            }
            ev.stopPropagation()
            ev.preventDefault();
            let nx = ev.clientX;
            let ny = ev.clientY;

            let nl = nx-(x-l);
            let nt = ny-(y-t);

            $('#divBox').css({
                top: nt+'px',
                left: nl+'px'
            })
        })
        $('#box').on('mouseup',function(event){
            event.preventDefault();
            isMove = false;
            $('#divBox').css('cursor','auto');
            $(this).off(event)
            $(this).off(moveEvent)
            return false;
        })
    })
    $('.bot').on('mousedown',function(e){
        e.stopPropagation()
        e.preventDefault();
        let isScale = true;
        let rect = document.getElementById('divBox').getBoundingClientRect();
        let oldWidth = $('#divBox').width();
        let oldHeight = $('#divBox').height();
        let oldX = e.clientX;
        let oldY = e.clientY;
        let oldLeft = parseInt($('#divBox').css('left'));
        let oldTop = parseInt($('#divBox').css('top'));
        let centerX = rect.left+rect.width/2;
        let centerY =  rect.top + rect.height / 2;
        let moveEvent = null;
        let w,h,t,l;
        let ceterIns = GetDistance(centerX,centerY,oldX,oldY);
        let angle = parseFloat($('#divBox')[0].dataset.angle) || 0;
        let jd = (angle*180/Math.PI)<0?360+(angle*180/Math.PI):(angle*180/Math.PI);
        let hd = jd*Math.PI/180;
        let _id = $(this).attr('id');
        $('#box').on('mousemove',function(ev){
            moveEvent = ev;
            if(!isScale){
                return
            }
            let newIns =  GetDistance(centerX,centerY,ev.clientX,ev.clientY);
            let ins = GetDistance(oldX,oldY,ev.clientX,ev.clientY)
            let isScaleBig = (newIns-ceterIns>=0)? true:false;// Decide whether to zoom in or out
            let dx = isScaleBig?ins:-ins;
            switch (_id){
                case 'tl':
                    var radioHd = 45*Math.PI/180;
                    var dxx = dx*Math.sin(radioHd);
                    var dl = dxx/2*(Math.sin(hd)-Math.cos(hd)-1);
                    var dh = dxx/2*(Math.cos(hd)+Math.sin(hd)+1);
                    w = oldWidth+dxx;
                    h = oldHeight+dxx;
                    l = oldLeft+dl;
                    t = oldTop-dh;
                    break;
                case 'tm':
                    var dh = dx-((dx/2)-(dx/2)*Math.cos(hd));
                    var dl = ((dx/2)*Math.sin(hd));
                    w = oldWidth;
                    h = oldHeight+dx;
                    l = oldLeft+dl;
                    t = oldTop-dh
                    break;
                case 'tr':
                    var radioHd = 45*Math.PI/180;
                    var dxx = dx*Math.sin(radioHd);
                    var dh = dxx/2*(Math.cos(hd)-Math.sin(hd)+1);
                    var dl = dxx/2*(Math.sin(hd)+Math.cos(hd)-1);
                    w = oldWidth+dxx;
                    h = oldHeight+dxx;
                    l = oldLeft+dl;
                    t = oldTop-dh;
                    break;
                case 'ml':
                    var dh = (dx/2)*Math.sin(hd);
                    var dl = dx-(dx/2-(dx/2)*Math.cos(hd));
                    w = oldWidth+ dx;
                    h = oldHeight;
                    l = oldLeft-dl;
                    t = oldTop- dh;
                    break;
                case 'mr':
                    var dh = (dx/2)*Math.sin(hd);
                    var dl = (dx/2)-((dx/2)*Math.cos(hd));
                    w = oldWidth+ dx;
                    h = oldHeight;
                    l = oldLeft-dl;
                    t = oldTop+ dh;
                    break;
                case 'bl':
                    var radioHd = 45*Math.PI/180;
                    var dxx = dx*Math.sin(radioHd);
                    var dl = dxx/2*(Math.sin(hd)+Math.cos(hd)+1);
                    var dh = dxx/2*(Math.sin(hd)-Math.cos(hd)+1);
                    w = oldWidth+dxx;
                    h = oldHeight+dxx;
                    l = oldLeft-dl;
                    t = oldTop-dh;
                    break;
                case 'bm':
                    var dh = (dx/2)-(dx/2)*Math.cos(hd);
                    var dl = ((dx/2)*Math.sin(hd));
                    w = oldWidth;
                    h = oldHeight+dx;
                    l = oldLeft-dl;
                    t = oldTop- dh;
                    break;
                case 'br':
                    var radioHd = 45*Math.PI/180;
                    var dxx = dx*Math.sin(radioHd);
                    var dl = dxx/2*(Math.sin(hd)-Math.cos(hd)+1);
                    var dh = dxx/2*(Math.sin(hd)+Math.cos(hd)-1);
                    w = oldWidth+dxx;
                    h = oldHeight+dxx;
                    l = oldLeft-dl;
                    t = oldTop+dh;
                    break;
                default:break;
            }
           
            $('#divBox').css({
                top: t+'px',
                left: l+'px',
                width: w+'px',
                height: h+'px'
            })
          
        })
        $('#box').on('mouseup',function(event){
            event.preventDefault();
            isScale = false;
            $(this).off(event);
            $(this).off(moveEvent);
            return false;
        })
    })
    $('.rotate').on('mousedown',function(e){
        e.stopPropagation()
        e.preventDefault();
        let rect = document.getElementById('divBox').getBoundingClientRect();
        let centerX = rect.left+rect.width/2;
        let centerY =  rect.top + rect.height / 2;
        let isMove = true;
        $('#divBox')[0].dataset.centerX = centerX;
        $('#divBox')[0].dataset.centerY = centerY;
        $('#divBox')[0].dataset.angle = getDragAngle(e);
        $('#box').on('mousemove',function(ev){
            moveEvent = ev;
            if(!isMove){
                return
            }
            let angle = getDragAngle(ev);
            // let jd = angle*180/Math.PI;

            // console.log(jd)
            $('#divBox').css({
                transform: `rotate(${angle}rad)`
            })

        })
        $('#box').on('mouseup',function(event){
            event.preventDefault();
            isMove = false;
            $('#divBox')[0].dataset.angle = getDragAngle(event);
            $(this).off(event)
            $(this).off(moveEvent)
            return false;
        })
    })
    function GetDistance( lat1,  lng1,  lat2,  lng2){
        dx = Math.abs(lat1 - lat2);
        dy = Math.abs(lng1 - lng2);
        var dis = Math.sqrt(Math.pow(dx,2)+Math.pow(dy,2));
        return parseInt(dis);
    }
    function getDragAngle(event){
        var startAngle = parseFloat($('#divBox')[0].dataset.angle) || 0;
        var center = {
            x: parseFloat($('#divBox')[0].dataset.centerX) || 0,
            y: parseFloat($('#divBox')[0].dataset.centerY) || 0,
        };
        var angle = Math.atan2(center.y - event.clientY, center.x - event.clientX);
        return angle - startAngle;
    }
})
</script>

</body>
</html>