js图片拖拽、缩放、添加图层功能(原创)
最近项目中完成的需求,仿百度地图中的功能:
要求:1.底层图可以拖拽、缩放。
2.拖拽一个图标,在底层图上对应位置添加一个标注点,该标注点位置要随底层图移动。
3.添加的标注点,可以拖动,删除。
主要知识点和难点就是各个浏览器的点击、拖拽、缩放事件兼容性,对js运动属性、运动偏移位置的了解,以及js面向对象的应用。
这里跟大家分享一下完成后的代码。
html代码主要知识点就是运动元素和底层元素的相对绝对定位,css代码不再贴出:
<div id="warp" style="position: relative;width: 100%;height: 100%;background: #d7d7d7;"> <img title="拖动" class="dragImg" id="dragImg" src="images/video_16px_566474.png"> <div class="dragAble bgDiv" id="block1" style="zoom:1;"> <img id="wheelImg" src="images/photo2FDIB963M30AI20009NOS.jpg" style="zoom:1;" title="底层图片"> <p>这段文字跟着div一起运动</p> </div> </div>
js代码,初始化:
1 var clearSlct = "getSelection" in window ? function() { 2 window.getSelection().removeAllRanges(); 3 } : function() { 4 document.selection.empty(); 5 }; 6 $(window).on("mouseup keyup", function() { 7 clearSlct(); 8 }); 9 document.getElementById('warp').oncontextmenu = function(e){ 10 e.preventDefault(); 11 }; 12 var dragDemo=new dragImg('block1','dragImg','wheelImg');
js代码,构造器+原型链进行面向对象开发:
function dragImg(bgDivId, imgId, bgImgId) { this.disX = 0; this.disY = 0; //初始点击点 this.xx = 0; this.yy = 0; //点击点相对于button的左上角的距离left,top this.marginX = 0; this.marginY = 0; //运动后底层图偏移量 this.isdrag = false; this.clicky = 0; this.clickx = 0; //初始点击点 this.oDragObj = null; //操作对象 this.init(bgDivId, imgId); this.initBgDiv(bgDivId); this.initMouseWheel(bgImgId); } dragImg.prototype = { init: function(bgDivId, imgId) { //图标拖拽 dragImg.imgId = imgId; dragImg.bgDivId = bgDivId; var drag_Img = document.getElementById(imgId), bg_div = document.getElementById(bgDivId); drag_Img.addEventListener('mousedown', dragDownEvent, false); drag_Img.addEventListener('mouseup', dragUpEvent, false); function dragDownEvent(e) { $('.dragBtnSpan').remove(); var oevent = e || e.event; if(oevent.button == 0) { var layerX = oevent.offsetX || oevent.layerX, layerY = oevent.offsetY || oevent.layerY; dragImg.disX = oevent.clientX - drag_Img.offsetLeft; dragImg.disY = oevent.clientY - drag_Img.offsetTop; dragImg.xx = oevent.clientX - drag_Img.offsetLeft; dragImg.yy = oevent.clientY - drag_Img.offsetTop; document.onmousemove = dragMoveEvent; } } function dragMoveEvent(e) { var oevent = e || e.event; var x = oevent.clientX, y = oevent.clientY; var offsetx = x - dragImg.disX, offsety = y - dragImg.disY; // console.log(offsetx,offsety); if(offsetx < 0) { offsetx = 0; } else if(offsetx > document.documentElement.clientWidth - drag_Img.offsetWidth) { offsetx = document.documentElement.clientWidth - drag_Img.offsetWidth; } if(offsety < 0) { offsety = 0; } else if(offsety > document.documentElement.clientHeight - drag_Img.offsetHeight) { offsety = document.documentElement.clientHeight - drag_Img.offsetHeight; } $("#" + dragImg.imgId).css('left', offsetx); $("#" + dragImg.imgId).css('top', offsety); } function dragUpEvent(e) { //拖拽结束,判断是否在允许放置的范围内(当前位置是否与底层图相交) var oevent = e || e.event; if(oevent.button == 0) { $('.dragBtn').remove(); var x = oevent.clientX, y = oevent.clientY; var zoom = bg_div.style.zoom; //缩放比例 var btn_X = drag_Img.offsetLeft, btn_Y = drag_Img.offsetTop, btn_width = drag_Img.offsetWidth * zoom, btn_height = drag_Img.offsetHeight * zoom, //缩放后长度,位置都会发生变化,需要*缩放倍率 map_X = bg_div.offsetLeft * zoom, map_Y = bg_div.offsetTop * zoom, map_left = bg_div.style.left, map_top = bg_div.style.top, map_width = bg_div.offsetWidth * zoom, map_height = bg_div.offsetHeight * zoom; var m = (btn_X + dragImg.xx > map_X + map_width) || (btn_X + dragImg.xx + btn_width < map_X); var n = (btn_height + btn_Y + dragImg.yy < map_Y) || (btn_Y + dragImg.yy > map_Y + map_height); if(m || n) { console.log('相离'); } else { //缩放后位置会偏移 var yesIE = IEVersion(); if(yesIE != -1) { //ie浏览器获取的就是实际偏移量,需要清除缩放倍率 if(yesIE > 8 || yesIE == 'Edge') { dragImg.marginX = bg_div.offsetLeft; dragImg.marginY = bg_div.offsetTop; } } else { dragImg.marginX = map_X, dragImg.marginY = map_Y; } var percentX = (x - dragImg.marginX - dragImg.xx) / zoom; var percentY = (y - dragImg.marginY - dragImg.yy) / zoom; // console.log('percentXxxxx',percentX); // console.log('percentYyyyy',percentY); LONG=percentX;//选定坐标点,赋值全局变量 LAT=percentY; var createImg = document.createElement('img'); createImg.src = 'resources/images/point_easyicon.png'; createImg.style.left = percentX + 'px'; createImg.style.top = percentY + 'px'; var btnId = 'btn_' + parseInt(percentX) + "_" + parseInt(percentY); createImg.setAttribute('id', btnId); createImg.setAttribute('class', 'dragBtn'); bg_div.appendChild(createImg); $("#" + btnId).on('mousedown', function(event) { if(event.button == 2) { $('.dragBtnSpan').remove(); var dragBtnSpan = document.createElement('ul'); var htm = '<li><a href="javascript:(0);" onclick="alert(123);">移动</a></li><li><a href="javascript:(0);" onclick="alert(456);">删除</a></li>'; dragBtnSpan.innerHTML = htm; dragBtnSpan.setAttribute('id', btnId + 'ul'); dragBtnSpan.setAttribute('class', 'dragBtnSpan'); bg_div.appendChild(dragBtnSpan); $('#' + btnId + 'ul').css('left', percentX + 10).css('top', percentY + 10).show(); } }); $("#dragImg").css('left', 10); $("#dragImg").css('top', 10); } document.onmousemove = null; } } }, initBgDiv: function(bgDivId) { //底层图拖拽 dragImg.bgDivId = bgDivId; var bg_div = document.getElementById(bgDivId); bg_div.addEventListener('mousedown', initDrag, false); document.onmouseup = new Function("dragImg.isdrag=false"); function initDrag(e) { if(e.button == 0) { var nn6 = document.getElementById && !document.all; var oDragHandle = nn6 ? e.target : event.srcElement; var topElement = "HTML"; while(oDragHandle.tagName != topElement && oDragHandle.className.indexOf("dragAble") == -1) { oDragHandle = nn6 ? oDragHandle.parentNode : oDragHandle.parentElement; } if(oDragHandle.className.indexOf("dragAble") != -1) { dragImg.isdrag = true; dragImg.oDragObj = oDragHandle; nTY = parseInt(dragImg.oDragObj.style.top + 0); //当前初始位置 dragImg.clicky = nn6 ? e.clientY : event.clientY; //点击位置 nTX = parseInt(dragImg.oDragObj.style.left + 0); dragImg.clickx = nn6 ? e.clientX : event.clientX; // oDragObj.style.zIndex++; document.onmousemove = moveMouse; return false; } } } function moveMouse(e) { if(dragImg.isdrag) { //初始位置+运动长度-点击时位置 var oevent = e || window.event; var clientX = oevent.clientX, clientY = oevent.clientY; var moveX = nTX + clientX - dragImg.clickx, moveY = nTY + clientY - dragImg.clicky; dragImg.oDragObj.style.top = moveY + "px"; dragImg.oDragObj.style.left = moveX + "px"; return false; } } }, initMouseWheel: function(bgImgId) { //底层图鼠标滚轮缩放 var bg_img = document.getElementById(bgImgId); // if (document.addEventListener) { bg_img.addEventListener('mousewheel', onWheelZoom, false); //IE9, Chrome, Safari, Oper // bg_img.addEventListener('wheel', onWheelZoom, false); //Firefox // bg_img.addEventListener('DOMMouseScroll', onWheelZoom, false); //Old Firefox // } else { // bg_img.attachEvent('onmousewheel', onWheelZoom); //IE 6/7/8 // } function onWheelZoom(e) { $('.dragBtnSpan').remove(); var obj = e.srcElement ? e.srcElement : e.target; var parentNode = obj.parentNode || obj; zoom = parseFloat(parentNode.style.zoom); //操作行内样式zoom,行内必须有zoom属性,不支持firefox var wheelDelta = event.wheelDelta || event.deltaY; tZoom = zoom + (wheelDelta > 0 ? 0.1 : -0.1); if(tZoom < 0.5) { return true; } parentNode.style.zoom = tZoom; return false; } }, getPosition: function(node) { var left = node.offsetLeft; //获取元素相对于其父元素的left值var left var top = node.offsetTop; current = node.offsetParent; // 取得元素的offsetParent // 一直循环直到根元素 while(current != null) { left += current.offsetLeft; top += current.offsetTop; current = current.offsetParent; } return { "left": left, "top": top }; } }
由于ie8和火狐需要更多的兼容性考虑,时间关系就没有支持ie8和火狐。
function IEVersion() { var version = -1; var userAgent = navigator.userAgent; var isIE = userAgent.indexOf('compatible') > -1 && userAgent.indexOf('MSIE') > -1; var isEdge = userAgent.indexOf('Edge') > -1 && !isIE; var isIE11 = userAgent.indexOf('Trident') > -1 && userAgent.indexOf('rv:11.0') > -1; if(isIE) { if(userAgent.indexOf("MSIE 5.5") > 0) { version = 5.5; } else if(userAgent.indexOf("MSIE 6.0") > 0) { version = 6; } else if(userAgent.indexOf("MSIE 7.0") > 0) { version = 7; } else if(userAgent.indexOf("MSIE 8.0") > 0 || (userAgent.indexOf("MSIE 9.0") > 0 && !window.innerWidth)) { version = 8; } else if(userAgent.indexOf("MSIE 9.0") > 0) { version = 9; } else { version = 10; } } else if(isEdge) { version = 'Edge'; } else if(isIE11) { version = 11; } else { version = -1; } return version; }
代码写的都很简单,关键位置都有注释,各位不要见笑。