实现的功能
在界面上将有一些图形,你可以随意拖动这些图形,可以把它们互相叠加在一起。一旦图形被拖入到黄色矩形框中,就不可以移动了
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;
}
}