您的当前位置:首页正文

SVG图形拖动功能的实现

2024-11-10 来源:个人技术集锦

实现的功能

在界面上将有一些图形,你可以随意拖动这些图形,可以把它们互相叠加在一起。一旦图形被拖入到黄色矩形框中,就不可以移动了

HTML文件

<!DOCTYPE html>

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title></title>
</head>
<body>
    <svg id="s" width="100%" height="100%" viewBox="0 0 1000 1000" xmlns="http://www.w3.org/2000/svg" οnlοad="init(evt)" οnmοusedοwn="Grab(evt)" οnmοusemοve="Drag(evt)" οnmοuseup="Drop(evt)">
        <rect id="BackDrop" x="-10%" y="-10%" width="110%" height="110%" fill="none" pointer-events="all" />
        <circle id="Blue_Circle" cx="30" cy="30" r="25" style="fill:blue;" />
        <text id="Draggable_Text" x="20" y="100" style="fill:red;font-size:18px;font-weight:bold;font-family:SimHei">可拖动文本</text>
        <rect id="Green_Rectangle" x="50" y="150" width="100" height="100" style="fill:green" />
        <g id="Box">
            <rect id="FolderRectangle" x="300" y="100" width="200" height="150" style="fill:yellow;stroke:brown;stroke-width:3;" />
        </g>
        <script type="application/javascript" xlink:href="13-7.js"></script>
    </svg>
</body>
</html>
JS文件

var svgDoc = null;
var svgRoot = null;
var trueCoords = null;//记录元素在视口中的实际坐标
var grabCoords = null;//表示视图经过缩放或移动后的点在视口中的坐标
var backDrop = null;
var GrabPoint = null;
var DragTarget = null;

function init(evt) {
    svgDoc = evt.target.ownerDocument;
    svgRoot = evt.target;
    //两个不显示的点
    trueCoords = svgRoot.createSVGPoint();
    GrabPoint = svgRoot.createSVGPoint();
    //定义了画布,作为拖动时间的透明背景层使用,接收所有的触发事件
    //这样做主要是为了避免因为拖动鼠标速度太快,而离开了被拖拽的元素,导致鼠标的onmousemove事件无法产生
    //有了这个层,无论被拖拽的元素是否跟得上鼠标的脚步,在这个层都能产生鼠标onmousemove事件
    backDrop = svgDoc.getElementById("BackDrop");
}

//获得当前元素在视口中的坐标位置的函数
function GetTrueCoords(evt) {       
    var newScale = svgRoot.currentScale;//currentScale获得当前视图的伸缩比例
    var translation = svgRoot.currentTranslate;//currentTranslate获得当前视图的平移量
    trueCoords.x = (evt.clientX - translation.x) / newScale;
    trueCoords.y = (evt.clientY - translation.y) / newScale;
}

//鼠标按下触发的事件
function Grab(evt) {
    
    var targetElement = evt.target;//取得要拖动的DOM Object
    GetTrueCoords(evt);
    if ("Box" == targetElement.parentNode.id) {//判断图形是否被拖入黄色框中
        DragTarget = null;//后续的拖动事件取消掉
        return;
    }
    if (backDrop != targetElement) {//不是在拖动背景
        DragTarget = targetElement;
    }
    
    DragTarget.parentNode.appendChild(DragTarget);//把要拖动的元素加入到它的父节点中,类似于在绘图软件中常见的”至于最上方“的操作

    DragTarget.setAttributeNS(null, "pointer-events", "none");//取消要拖动元素的鼠标接收事件
    //这样可以保证当鼠标释放时所触发的事件的”主人“不是要拖动的元素本身,而是它所覆盖的元素,画布或其他元素
    
    var Matrix = DragTarget.getCTM();//获取当前SVG的坐标转换矩阵 
    GrabPoint.x = trueCoords.x - Number(Matrix.e);//定义元素移动后在视图中的坐标
    GrabPoint.y = trueCoords.y - Number(Matrix.f);
}

//拖动鼠标触发的事件
function Drag(evt) {
    GetTrueCoords(evt);//获取当前元素在视口的实际坐标
    if (DragTarget) { //判断被拖动元素是否存在
        var newX = trueCoords.x - GrabPoint.x;
        var newY = trueCoords.y - GrabPoint.y;
        DragTarget.setAttributeNS(null, "transform", "translate(" + newX + "," + newY + ")");//设置元素的平移变化参数 实际效果就是被拖动的元素随着鼠标不断移动
    }

    
}

function Drop(evt) {//evt不是要拖动的元素本身,而是它所覆盖的元素,画布或其他元素
    if (DragTarget) {
        var targetElement = evt.target; 
        DragTarget.setAttributeNS(null, "pointer-events", "all");//恢复要拖动元素的鼠标接收事件
        if ("Box" == targetElement.parentNode.id) {
            targetElement.parentNode.appendChild(DragTarget);
            alert(DragTarget.id + " 已经被拖入黄色箱子中");
        } else {
            //alert(DragTarget.id + " 已经位于" + targetElement.id + "之上");
        }
        DragTarget = null;
    }
}



显示全文