div拖拽缩放jquery插件编写——带8个控制点
项目中需要对div进行拖拽缩放,需要有控制面板8个控制点的那种,原以为这么常见的效果应该能搜索到很多相关插件,然而可以完成拖拽的实繁,却找不到我想要的,还是自己动手丰衣足食吧
效果预览(只支持pc端)
思路
一、舞台拖拽项定义
拖拽以及缩放需要有一个范围,姑且管这个叫舞台(stage)。另外,在舞台范围内,如何以一种简单的方式定义拖拽项?可以通过给div增加一个拖拽class(例如:resize-item),拖拽项应该是absolute布局,舞台是relative/absolute布局
所以拖拽类需要有如下两个参数
/**
* 默认参数
*/
var defaultOpts = {
stage: document, //舞台,默认为stage
itemClass: 'resize-item', //可缩放的类名
};
/**
* 定义类
*/
var ZResize = function(options) {
this.options = $.extend({}, defaultOpts, options);
this.init();
}
二、生成控制面板

- 面板:为了尽可能少的影响到拖拽项,就不直接在拖拽项上生成控制点,而是为拖拽项增加一个半透明层作为控制面板,控制面板尺寸位置和拖拽项一致,将控制面板插入拖拽项(由于都是absolute布局,不影响原内容),可以更好的控制位置和一一对应
var width = $(this).width();
var height = $(this).height();
var resizePanel = $('<div class"resize-panel"></div>');
resizePanel.css({
width: width,
height: height,
top: 0,
left: 0,
position: 'absolute',
'background-color': 'rgba(0,0,0,0.5)',
cursor: 'move',
display: 'none'
});
self.appendHandler(resizePanel, $(this));
- 控制点:为控制面板增加东、南、西、北、东北、西北、西南、东南控制点,为每个控制点设置对应的cursor
'cursor': 'n-resize' //北
'cursor': 's-resize' //南
'cursor': 'e-resize' //东
'cursor': 'w-resize' //西
'cursor': 'ne-resize' //东北
'cursor': 'nw-resize' //西北
'cursor': 'se-resize' //东南
'cursor': 'sw-resize' //西南
三、缩放
- 每个控制点影响的属性不一样
北(上):
高度(height)
位置y(拖拽上边,应该保持下边固定,所以高度变化之后位置也要变化)
南(下):
高度(height)
东(右):
宽度(width)
西(左):
宽度(width)
位置x(拖拽左边,应该保持右边固定,所以宽度变化之后位置也要变化)
东北、西北、东南、西南 以上两两结合
- 监听控制点mousedown,分别定义一个标志,并且记录下原始位置,如:
//西
var wmove = false;
el.on('mousedown','.w', function(e) {
ox = e.pageX;//原始x位置
ow = el.width();
oleft = parseInt(org.css('left').replace('px', ''));
wmove = true;
});
- 监听控制面板的mousedown,同样定义一个标志,用于拖动(drag)
- 监听舞台(stage)的mousemove(注意这里不是监听控制点的mousemove,因为控制点实在是太小,无法灵敏的拖动),判断各个控制点以及控制面板mousedown的标志分别对宽高和位置进行处理。处理的逻辑为:touchmove过程中的
e.pageX/e.pageY - ox/oy(原始) = 偏移量,对于第一点中提到的每个控制点影响的属性,根据偏移量进行变化

- 监听舞台(stage)的mouseup事件(这里同样不能是控制点的mouseup),把所有的mousedown标志重置为false
pc端的mouse事件不同于手机端的touch事件,touchstart->touchmove->touchend触发有顺序性,mouse事件没有顺序性,未触发mousedown也能触发mousemove,所以需要设置标志来判断
四、控制面板的出现隐藏
控制面板初始化的时候,应该是隐藏的,只有点击对应的拖拽项的时候才出现,并且点击舞台空白部分,需要隐藏控制面板(组织事件冒泡)
/**
+ 点击item显示拖拽面板
*/
bindTrigger: function(el) {
var self = this;
el.on('click', function(e) {
//组织事件冒泡,不然会被舞台触发,舞台触发会把控制面板隐藏掉
e.stopPropagation();
self.triggerResize(el);
});
},
/**
+ 点击舞台空闲区域 隐藏缩放面板
*/
bindHidePanel: function(el) {
var stage = this.options.stage;
var itemClass = this.options.itemClass;
$(stage).bind('click', function() {
$('.' + itemClass).children('div').css({
display: 'none'
});
})
}
备注:
<!doctype html>
<html> <head>
<meta charset="utf-8">
<title>jQuery拖拽放大缩小插件idrag</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css">
.item1 {
width: 405px;
height: 291px;
cursor: move;
position: absolute;
top: 30px;
left: 30px;
background-color: #FFF;
border: 1px solid #CCCCCC;
-webkit-box-shadow: 10px 10px 25px #ccc;
-moz-box-shadow: 10px 10px 25px #ccc;
box-shadow: 10px 10px 25px #ccc;
} .item2 {
width: 200px;
height: 100px;
cursor: move;
position: absolute;
top: 400px;
left: 100px;
background-color: #FFF;
border: 1px solid #CCCCCC;
-webkit-box-shadow: 10px 10px 25px #ccc;
-moz-box-shadow: 10px 10px 25px #ccc;
box-shadow: 10px 10px 25px #ccc;
line-height: 100px;
text-align: center;
} body {
background-color: #F3F3F3;
}
</style>
</head> <body>
<div class="resize-item item1">
<img src="data:images/dog.png" width="100%" height="100%">
</div> <div class="resize-item item2">
你是我的小小狗
</div>
<script src="js/jquery.min.js"></script>
<script type="text/javascript" src='js/jquery.ZResize.js'></script>
<script type="text/javascript">
new ZResize();
</script>
</body> </html>
相应的js插件jquery.ZResize.js为:
(function($) {
/**
* 默认参数
*/
var defaultOpts = {
stage: document, //舞台
itemClass: 'resize-item', //可缩放的类名
};
/**
* 定义类
*/
var ZResize = function(options) {
this.options = $.extend({}, defaultOpts, options);
this.init();
}
ZResize.prototype = {
init: function() {
this.initResizeBox();
},
/**
* 初始化拖拽item
*/
initResizeBox: function() {
var self = this;
$('.' + self.options.itemClass).each(function() {
//创建面板
var width = $(this).width();
var height = $(this).height();
var resizePanel = $('<div class"resize-panel"></div>');
resizePanel.css({
width: width,
height: height,
top: 0,
left: 0,
position: 'absolute',
'background-color': 'rgba(0,0,0,0.5)',
cursor: 'move',
display: 'none'
});
self.appendHandler(resizePanel, $(this));
/**
* 创建控制点
*/
var n = $('<div class="n"></div>');//北
var s = $('<div class="s"></div>');//南
var w = $('<div class="w"></div>');//西
var e = $('<div class="e"></div>');//东
var ne = $('<div class="ne"></div>');//东北
var nw = $('<div class="nw"></div>');//西北
var se = $('<div class="se"></div>');//东南
var sw = $('<div class="sw"></div>');//西南
//添加公共样式
self.addHandlerCss([n, s, w, e, ne, nw, se, sw]);
//添加各自样式
n.css({
'top': '-4px',
'margin-left': '-4px',
'left': '50%',
'cursor': 'n-resize'
});
s.css({
'bottom': '-4px',
'margin-left': '-4px',
'left': '50%',
'cursor': 's-resize'
});
e.css({
'top': '50%',
'margin-top': '-4px',
'right': '-4px',
'cursor': 'e-resize'
});
w.css({
'top': '50%',
'margin-top': '-4px',
'left': '-4px',
'cursor': 'w-resize'
});
ne.css({
'top': '-4px',
'right': '-4px',
'cursor': 'ne-resize'
});
nw.css({
top: '-4px',
'left': '-4px',
'cursor': 'nw-resize'
});
se.css({
'bottom': '-4px',
'right': '-4px',
'cursor': 'se-resize'
});
sw.css({
'bottom': '-4px',
'left': '-4px',
'cursor': 'sw-resize'
});
// 添加项目
self.appendHandler([n, s, w, e, ne, nw, se, sw], resizePanel);
//绑定拖拽缩放事件
self.bindResizeEvent(resizePanel, $(this));
//绑定触发事件
self.bindTrigger($(this));
});
self.bindHidePanel();
},
//控制点公共样式
addHandlerCss: function(els) {
for(var i = 0; i < els.length; i++) {
el = els[i];
el.css({
position: 'absolute',
width: '8px',
height: '8px',
background: '#ff6600',
margin: '0',
'border-radius': '2px',
border: '1px solid #dd5500',
});
}
},
/**
* 插入容器
*/
appendHandler: function(handlers, target) {
for(var i = 0; i < handlers.length; i++) {
el = handlers[i];
target.append(el);
}
},
/**
* 显示拖拽面板
*/
triggerResize: function(el) {
var self = this;
el.siblings('.' + self.options.itemClass).children('div').css({
display: 'none'
});
el.children('div').css({
display: 'block'
});
},
/**
* 拖拽事件控制 包含8个缩放点 和一个拖拽位置
*/
bindResizeEvent: function(el) {
var self = this;
var ox = 0; //原始事件x位置
var oy = 0; //原始事件y位置
var ow = 0; //原始宽度
var oh = 0; //原始高度
var oleft = 0; //原始元素位置
var otop = 0;
var org = el.parent('div');
//东
var emove = false;
el.on('mousedown','.e', function(e) {
ox = e.pageX;//原始x位置
ow = el.width();
emove = true;
});
//南
var smove = false;
el.on('mousedown','.s', function(e) {
oy = e.pageY;//原始x位置
oh = el.height();
smove = true;
});
//西
var wmove = false;
el.on('mousedown','.w', function(e) {
ox = e.pageX;//原始x位置
ow = el.width();
wmove = true;
oleft = parseInt(org.css('left').replace('px', ''));
});
//北
var nmove = false;
el.on('mousedown','.n', function(e) {
oy = e.pageY;//原始x位置
oh = el.height();
nmove = true;
otop = parseInt(org.css('top').replace('px', ''));
});
//东北
var nemove = false;
el.on('mousedown','.ne', function(e) {
ox = e.pageX;//原始x位置
oy = e.pageY;
ow = el.width();
oh = el.height();
nemove = true;
otop = parseInt(org.css('top').replace('px', ''));
});
//西北
var nwmove = false;
el.on('mousedown','.nw', function(e) {
ox = e.pageX;//原始x位置
oy = e.pageY;
ow = el.width();
oh = el.height();
otop = parseInt(org.css('top').replace('px', ''));
oleft = parseInt(org.css('left').replace('px', ''));
nwmove = true;
});
//东南
var semove = false;
el.on('mousedown','.se', function(e) {
ox = e.pageX;//原始x位置
oy = e.pageY;
ow = el.width();
oh = el.height();
semove = true;
});
//西南
var swmove = false;
el.on('mousedown','.sw', function(e) {
ox = e.pageX;//原始x位置
oy = e.pageY;
ow = el.width();
oh = el.height();
swmove = true;
oleft = parseInt(org.css('left').replace('px', ''));
});
//拖拽
var drag = false;
el.on('mousedown', function(e) {
ox = e.pageX;//原始x位置
oy = e.pageY;
otop = parseInt(org.css('top').replace('px', ''));
oleft = parseInt(org.css('left').replace('px', ''));
drag = true;
});
$(self.options.stage).on('mousemove', function(e) {
if(emove) {
var x = (e.pageX - ox);
el.css({
width: ow + x
});
org.css({
width: ow + x
});
} else if(smove) {
var y = (e.pageY - oy);
el.css({
height: oh + y
});
org.css({
height: oh + y
});
} else if(wmove) {
var x = (e.pageX - ox);
el.css({
width: ow - x,
// left: oleft + x
});
org.css({
width: ow - x,
left: oleft + x
});
} else if(nmove) {
var y = (e.pageY - oy);
el.css({
height: oh - y,
// top: otop + y
});
org.css({
height: oh - y,
top: otop + y
});
} else if(nemove) {
var x = e.pageX - ox;
var y = e.pageY - oy;
el.css({
height: oh - y,
// top: otop + y,
width: ow + x
});
org.css({
height: oh - y,
top: otop + y,
width: ow + x
});
} else if(nwmove) {
var x = e.pageX - ox;
var y = e.pageY - oy;
el.css({
height: oh - y,
// top: otop + y,
width: ow - x,
// left: oleft + x
});
org.css({
height: oh - y,
top: otop + y,
width: ow - x,
left: oleft + x
});
} else if(semove) {
var x = e.pageX - ox;
var y = e.pageY - oy;
el.css({
width: ow + x,
height: oh + y
});
org.css({
width: ow + x,
height: oh + y
});
} else if(swmove) {
var x = e.pageX - ox;
var y = e.pageY - oy;
el.css({
width: ow - x,
// left: oleft + x,
height: oh + y
});
org.css({
width: ow - x,
left: oleft + x,
height: oh + y
});
} else if(drag) {
var x = e.pageX - ox;
var y = e.pageY - oy;
org.css({
left: oleft + x,
top: otop + y
});
}
}).on('mouseup', function(e) {
emove = false;
smove = false;
wmove = false;
nmove = false;
nemove = false;
nwmove = false;
swmove = false;
semove = false;
drag = false;
});
},
/**
* 点击item显示拖拽面板
*/
bindTrigger: function(el) {
var self = this;
el.on('click', function(e) {
e.stopPropagation();
self.triggerResize(el);
});
},
/**
* 点击舞台空闲区域 隐藏缩放面板
*/
bindHidePanel: function(el) {
var stage = this.options.stage;
var itemClass = this.options.itemClass;
$(stage).bind('click', function() {
$('.' + itemClass).children('div').css({
display: 'none'
});
})
}
}
window.ZResize = ZResize;
})(jQuery);
源码链接:https://github.com/zengwenfu/z-resize
作者:小虫巨蟹
链接:https://www.jianshu.com/p/822afede7489
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
div拖拽缩放jquery插件编写——带8个控制点的更多相关文章
- div拖拽效果 JQuery
<!DOCTYPE html> <html> <head> <meta name="description" content=" ...
- div/dom元素拖拽缩放插件,纯js实现拖拽缩放,不依赖jQuery~
产品需求,需要用到对div(dom)进行拖拽缩放操作,看到有好多插件,要么依赖jQuery,要么文件太大. 封装了一个插件,不压缩状态下5KB. html <!DOCTYPE html> ...
- Vue富文本编辑器(图片拖拽缩放)
富文本编辑器(图片拖拽缩放) 需求: 根据业务要求,需要能够上传图片,且上传的图片能在移动端中占满屏幕宽度,故需要能等比缩放上传的图片,还需要能拖拽.缩放.改变图片大小.尝试多个第三方富文本编辑器,很 ...
- jQuery插件编写及链式编程模型小结
JQuery极大的提高了我们编写JavaScript的效率,让我们可以愉快的编写代码,做出各种特效.大多数情况下,我们都是使用别人开发的JQuery插件,今天我们就来看看如何把我们常用的功能做出JQu ...
- jQuery插件编写及链式编程模型
jQuery插件编写及链式编程模型小结 JQuery极大的提高了我们编写JavaScript的效率,让我们可以愉快的编写代码,做出各种特效.大多数情况下,我们都是使用别人开发的JQuery插件,今天我 ...
- 实现Div拖拽
直观的理解div拖拽:当鼠标对着可拖拽部分按住后并拖动,div会跟着鼠标一起运动,并且其运动空间限制在浏览器内部,当放开鼠标时,则div停止运动. 实现div拖拽需要三个重要的事件: (1)onmou ...
- html之div拖拽,html5拖拽
html之div拖拽 http://www.w3school.com.cn/html5/html_5_draganddrop.asp
- 运用DIV拖拽实现resize和碰撞检测
运用DIV拖拽实现resize和碰撞检测 Div由拖拽改变大小 演示demo 当我们运用html元素"textarea"写一个文本输入框时,浏览器会自动生成以下样式 用鼠标拖动右下 ...
- 纯js实现DIV拖拽
写代码的时候遇到需要对绝对布局的div进行拖拽的功能,起初为了省事直接在网上扒拉了一番,看到大神张鑫旭的一篇文章<JavaScript实现最简单的拖拽效果>,便直接拿来使用(膜拜大神).但 ...
随机推荐
- COMMIT - 提交当前事务
SYNOPSIS COMMIT [ WORK | TRANSACTION ] DESCRIPTION 描述 COMMIT 提交当前事务. 所有事务的更改都将为其他事务可见,而且保证当崩溃发生时的可持续 ...
- CAD嵌套打印(com接口版)
当用户需要打印两个CAD控件的图纸时,可以采用嵌套打印实现.实现嵌套打印功能,首先将两个CAD控件放入网页中,C#代码如下: private void BatchPrintDialog() { MxD ...
- print keys %map_function 输出 散列的值: OK_funcsplit_funcpackage_VAR
my %map_function = ( 88 "OK_func" => "open_statement", 89 &qu ...
- 第3节 hive高级用法:14、hive的数据压缩
六.hive的数据压缩 在实际工作当中,hive当中处理的数据,一般都需要经过压缩,前期我们在学习hadoop的时候,已经配置过hadoop的压缩,我们这里的hive也是一样的可以使用压缩来节省我们的 ...
- 根据数据库表自动生成实体类、xml和dao---mybatis
网盘链接: https://pan.baidu.com/s/1AVGz0bDa_Y5zjk7vXa2eHw 提取码: 2gr6 1.记事本打开generatorConfig.xml文件 2(1,2,3 ...
- BZOJ 1711 吃饭dining/Luogu P1402 酒店之王 拆点+最大流流匹配
题意: (吃饭dining)有F种食物和D种饮料,每种食物或饮料只能供一头牛享用,且每头牛只享用一种食物和一种饮料.现在有n头牛,每头牛都有自己喜欢的食物种类列表和饮料种类列表,问最多能使几头牛同时享 ...
- LeetCode(53) Maximum Subarray
题目 Find the contiguous subarray within an array (containing at least one number) which has the large ...
- python pip 安装一些包找不到的问题 Could not find a version that satisfies....
有时我们使用下载python 自带的pip 安装一些工具包时,会报如下错误 找不到满意的版本,这时就是我们的pip可能需要升级了,所以使用 python -m pip install --upgrad ...
- 如何抓取崩溃的log日志
4.手机录屏工具的推荐 Andriod:录屏大师,易录屏等等. iOS:AirPlayer,iTools. 5.如何抓取崩溃的log日志? android闪退获取日志方法: 1.下载adb工具包 2. ...
- 九度oj 题目1202:排序
题目1202:排序 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:28802 解决:9408 题目描述: 对输入的n个数进行排序并输出. 输入: 输入的第一行包括一个整数n(1<=n ...