Zhiqim UI是一套集成Javascript库、Css库、Font库、常用ico图标等,并在其上开发的大量UI组件组成的前端开发套件。
zhiqim_drag.js27KB
/*
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
*
* https://zhiqim.org/project/zhiqim_framework/zhiqim_ui.htm
*
* Zhiqim UI is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
+(function(Z)
{//BEGIN
// @version v1.1.0 @author zouzhigang 2015-11-12 新建与整理
// 调用举例:
// var dragList = new Z.DragList({pid: "pid", callback: onCallback});
// dragList.setBorderColor("#000"); 设置边框颜色
// dragList.setMinWidthHeight(30, 30); 缩放最小宽高
// dragList.setResizeRateFalse(); 缩放不按比例
// dragList.addImage("/inc/images/abc.png");
// dragList.addHtml(html);
Z.DragList = Z.Class.newInstance();
Z.DragList.prototype =
{
defaults:
{
//以下为Z.DragList的参数
isClickSelected: true,
selectLast: true,
callback: null,
//以下为Z.DragElem需要的参数
pid: null, //1.父层ID,用于拖拽时不超过父层
isResizeRate: true, //2.是否强制比例缩放
isDeleteIco: true, //3.是否在右上角显示删除图标
left:0, //4.默认左值
top:0, //5.默认上值
minWidth: 20, //6.默认拖放图片最小宽度
minHeight: 20, //7.默认拖放图片最小高度
cursorWidth: 10, //8.默认鼠标靠右边缘宽度时显示不同手势
cursorHeight: 10, //9.默认鼠标靠下边缘高度时显示不同手势
borderColor: "transparent", //10未选中的边框颜色,默认是透明色
borderSelected: "red", //11选中的边框颜色,默认是红色
bgColor: "transparent", //12未选中的背景颜色
bgSelected: "transparent" //13选中的背景颜色
},
init: function()
{//构造函数
if (!this.pid || !Z.D.has(this.pid)){
Z.alert("拖拽层父层[pid]必须指定");
}
//取得父层数据
this.$parent = Z("#"+this.pid);
this.$parent.css({boxSizing:"content-box"}); //强制定义边框在外面
this.pBorderLeft = Z.S.prefixNum(this.$parent.css("borderLeftWidth")); //拖放层边框
this.pBorderRight = Z.S.prefixNum(this.$parent.css("borderRightWidth")); //拖放层边框
this.pBorderTop = Z.S.prefixNum(this.$parent.css("borderTopWidth")); //拖放层边框
this.pBorderBottom = Z.S.prefixNum(this.$parent.css("borderBottomWidth")); //拖放层边框
this.pWidth = this.$parent.offsetWidth() - this.pBorderLeft - this.pBorderRight; //拖放层宽度
this.pHeight = this.$parent.offsetHeight() - this.pBorderTop - this.pBorderBottom; //拖放层高度
this.list = [];
this.current = null;
//定义全文档键盘按下方法
Z(document).keydown(this.doKeyDown, this);
},
execute: function()
{//执行为空即可,统一在初始化中处理
},
size: function()
{
return this.list.length;
},
selected: function()
{
this.doPrivateUnselected();
if (this.current != null){
this.current.bordered();
this.current.backgrounded();
}
},
remove: function()
{
if (this.current != null){
this.current.remove();
}
},
getWidth:function()
{
return (this.current == null)?0:this.current.getWidth();
},
getHeight:function()
{
return (this.current == null)?0:this.current.getHeight();
},
getAttr: function(key)
{
return (this.current == null)?0:this.current.$elem.attr(key);
},
setHtml: function(html)
{
if (this.current != null){
this.current.$elem.html(html);
}
},
setSizeRateWidth: function(_width)
{
if (this.current != null){
this.current.setSizeRateWidth(_width);
}
},
setPositionPoint: function(_pos)
{
if (this.current != null){
this.current.setPositionPoint(_pos);
}
},
add: function(drag)
{
if (this.selectLast)
{//添加时选中
this.current = drag;
this.selected();
this.doPrivateCallback(drag, "onCreated");
}
drag.callback = Z.bind(this.doCallback, this);
this.list.push(drag);
},
addImage: function(src, styles, attrs, isResizeRate, isDeleteIco)
{
var drag = new Z.DragElem();
drag.$parent = this.$parent;
drag.pWidth = this.pWidth;
drag.pHeight = this.pHeight;
drag.isResizeRate = (Z.T.isBoolean(isResizeRate))?isResizeRate:this.isResizeRate;
drag.isDeleteIco = (Z.T.isBoolean(isDeleteIco))?isDeleteIco:this.isDeleteIco;
drag.minWidth = this.minWidth;
drag.minHeight = this.minHeight;
drag.cursorWidth = this.cursorWidth;
drag.cursorHeight = this.cursorHeight;
drag.borderColor = this.borderColor;
drag.borderSelected = this.borderSelected;
drag.bgColor = this.bgColor;
drag.bgSelected = this.bgSelected;
drag.$elem = Z(document.createElement("img"));
drag.$elem.load(function()
{//webkit每次加载有延迟,firefox首次加载有延迟,IE没有但要放置到dom上才行
drag.execute();
this.add(drag);
}, this);
drag.$elem.css({left: this.left, top: this.top});
drag.$elem.attr("src", src);
drag.$elem.css(styles);
drag.$elem.attr(attrs);
},
addHtml: function(html, styles, attrs, isResizeRate, isDeleteIco)
{
var drag = new Z.DragElem();
drag.$parent = this.$parent;
drag.pWidth = this.pWidth;
drag.pHeight = this.pHeight;
drag.isResizeRate = (Z.T.isBoolean(isResizeRate))?isResizeRate:this.isResizeRate;
drag.isDeleteIco = (Z.T.isBoolean(isDeleteIco))?isDeleteIco:this.isDeleteIco;
drag.minWidth = this.minWidth;
drag.minHeight = this.minHeight;
drag.cursorWidth = this.cursorWidth;
drag.cursorHeight = this.cursorHeight;
drag.borderColor = this.borderColor;
drag.borderSelected = this.borderSelected;
drag.bgColor = this.bgColor;
drag.bgSelected = this.bgSelected;
drag.$elem = Z(document.createElement("div"));
drag.$elem.html(html);
drag.$elem.css(styles);
drag.$elem.attr(attrs);
drag.execute();
drag.unbordered();
drag.unbackgrounded();
this.add(drag);
},
doKeyDown:function(e)
{
if (this.current == null)
return;
//如果找到一个且是上下左右删除键,则停止事件冒泡
var key = Z.E.key(e);
switch(key)
{
case Z.E.KEY.LEFT: this.current.doLeft();Z.E.forbidden(e);break;
case Z.E.KEY.UP: this.current.doUp();Z.E.forbidden(e);break;
case Z.E.KEY.RIGHT: this.current.doRight();Z.E.forbidden(e);break;
case Z.E.KEY.DOWN: this.current.doDown();Z.E.forbidden(e);break;
case Z.E.KEY.DELETE: this.current.remove();Z.E.forbidden(e);break;
}
},
/*******************************************************/
//以下为键盘操作属性
/*******************************************************/
doLeft:function()
{//左
if (this.current != null){
this.current.doLeft();
}
},
doUp:function()
{//上
if (this.current != null){
this.current.doUp();
}
},
doRight:function()
{//右
if (this.current != null){
this.current.doRight();
}
},
doDown:function()
{//下
if (this.current != null){
this.current.doDown();
}
},
doWidthIncrease:function()
{//加宽
if (this.current != null){
this.current.doWidthIncrease();
}
},
doWidthDecrease:function()
{//减宽
if (this.current != null){
this.current.doWidthDecrease();
}
},
doHeightIncrease:function()
{//加高
if (this.current != null){
this.current.doHeightIncrease();
}
},
doHeightDecrease:function()
{//减高
if (this.current != null){
this.current.doHeightDecrease();
}
},
doCallback: function(drag, event)
{
if ("onRemoved" == event)
{//删除
Z.AR.remove(this.list, drag);
this.current = this.selectLast?Z.AR.last(this.list):null;
this.selected();
this.doPrivateCallback(drag, event);
return;
}
if (this.isClickSelected)
{//点击即选中
if ("onMouseDown" == event){
this.current = drag;
this.selected();
}else if ("onMouseOver" == event){
drag.bordered();
}else if ("onMouseOut" == event && this.current != drag){
drag.unbordered();
}
}
else
{//移入即选中
this.current = drag;
this.selected();
}
this.doPrivateCallback(drag, event);
},
/*******************************************************/
//以下为内部私有方法
/*******************************************************/
doPrivateUnselected: function()
{//全部取消选中
Z.each(this.list, function(d){
d.unbordered();
d.unbackgrounded();
});
},
doPrivateCallback: function(drag, event)
{//回调
if (Z.T.isFunction(this.callback)){
this.callback(drag, event);
}
}
};
Z.DragElem = Z.Class.newInstance();
Z.DragElem.prototype = //定义这个新类的结构
{
defaults:
{
pid: null,
callback:null,
isResizeRate: true,//是否强制比例缩放
isDeleteIco: true,
minWidth: 20,//默认拖放图片最小宽度
minHeight: 20,//默认拖放图片最小高度
cursorWidth: 20,
cursorHeight: 20,
borderColor: "#f00",
$parent: null,
$elem: null,
borderColor: "transparent",
borderSelected: "red",
bgColor: "transparent",
bgSelected: "transparent"
},
execute:function()
{//执行函数
//设置拖放图到父层,并控制不超过父层
this.$elem.css({position: "absolute"}).appendTo(this.$parent);
this.left = this.$elem.offsetLeft();
this.top = this.$elem.offsetTop();
this.rate = this.$elem.offsetWidth() / this.$elem.offsetHeight();
var currentWidth = Math.max(Math.min(this.$elem.offsetWidth(), this.pWidth), this.minWidth);
var currentHeight = Math.max(Math.min(this.$elem.offsetHeight(), this.pHeight), this.minHeight);
var _maxWidth = this.pWidth - this.left;
var _maxHeight = this.pHeight - this.top;
var wh = this.doPrivateResizeRate(currentWidth, currentHeight, _maxWidth, _maxHeight);
this.width = wh[0];
this.height = wh[1];
this.$elem.css({width: this.width, height: this.height});
//增加一个边框层覆盖拖放图,用于事件控制
this.$border = Z("<div>").appendTo(this.$parent);
this.$border.css({position: "absolute", left: this.left, top: this.top, width: this.width, height: this.height});
//增加一个删除图标跟随拖放图
if (this.isDeleteIco)
{
this.$delete = Z("<div>").appendTo(this.$border);
this.$delete.css({position: "absolute", top: 1, right: 1, cursor: "pointer"})
.html("<span class='z-px16 z-lh16 z-color-red'>×</span>")
.click(this.remove, this);
}
//定义移动和缩放的手手势和临时计算数据
this.cursor = null; //移动或缩放手势,move表示移动,nw-resize比例缩放,e-resize左右缩放,n-resize上下缩放
this.moveStartX = 0; //移动时鼠标开始位置坐标X
this.moveStartY = 0; //移动时鼠标开始位置坐标Y
this.resizeStartX = 0; //缩放时鼠标开始位置坐标X
this.resizeStartY = 0; //缩放时鼠标开始位置坐标Y
//定义鼠标移入移出按下的事件方法
this.$border.mouseover(this.doMouseOver, this)
.mouseout(this.doMouseOut, this)
.mousedown(this.doMouseDown, this);
},
remove:function()
{
if (this.isDeleteIco){
this.$delete.remove();
}
this.$border.remove();
this.$elem.remove();
this.doPrivateCallback("onRemoved");
},
bordered: function()
{//移入换选中边框
this.$border.css({border: "1px solid " + this.borderSelected});
},
unbordered:function()
{//移出换原始边框
this.$border.css({border: "1px solid " + this.borderColor});
},
backgrounded: function()
{//点击换背景
this.$elem.css({backgroundColor: this.bgSelected});
},
unbackgrounded:function()
{//取消选中
this.$elem.css({backgroundColor: this.bgColor});
},
/*******************************************************/
//获取属性
/*******************************************************/
getLeft:function()
{
return this.$elem.offsetLeft();
},
getTop:function()
{
return this.$elem.offsetTop();
},
getWidth:function()
{
return this.$elem.offsetWidth();
},
getHeight:function()
{
return this.$elem.offsetHeight();
},
getAttr: function(key)
{
return this.$elem.attr(key);
},
/*******************************************************/
//设置属性
/*******************************************************/
setBorderColor: function(_borderColor)
{//设置边框颜色
this.borderColor = _borderColor;
},
setMinWidthHeight:function(_minWidth, _minHeight)
{//设置最小宽高
this.minWidth = _minWidth;
this.minHeight = _minHeight;
},
setResizeRateFalse:function()
{//设置缩放比例为false
this.isResizeRate = false;
},
setSize:function(_width, _height)
{//设置指定的宽高
var _maxWidth = this.pWidth - this.$elem.offsetLeft();
var _maxHeight = this.pHeight - this.$elem.offsetTop();
var currentWidth = Math.max(_width, this.minWidth);
var currentHeight = Math.max(_height, this.minHeight);
currentWidth = Math.min(currentWidth, _maxWidth);
currentHeight = Math.min(currentHeight, _maxHeight);
this.doPrivateCss({width: currentWidth, height: currentHeight});
},
setSizeRateWidth:function(_width)
{//设置指定的宽指定的比例计算高
var _maxWidth = this.pWidth - this.$elem.offsetLeft();
var _maxHeight = this.pHeight - this.$elem.offsetTop();
var currentWidth = Math.min(Math.max(_width, this.minWidth), _maxWidth);
var currentHeight = (currentWidth / this.rate).toFixed(0);
if (currentHeight > _maxHeight)
{//超高
currentHeight = _maxHeight;
currentWidth = (currentHeight * this.rate).toFixed(0);
}
//超矮
if (currentHeight < this.minHeight)
{
currentHeight = this.minHeight;
currentWidth = (currentHeight * this.rate).toFixed(0);
}
this.doPrivateCss({width: currentWidth, height: currentHeight});
},
setSizeRateHeight:function(_height)
{//设置指定的高,然后按指定的比例计算宽
var _maxWidth = this.pWidth - this.$elem.offsetLeft();
var _maxHeight = this.pHeight - this.$elem.offsetTop();
var currentHeight = Math.min(Math.max(_height, this.minHeight), _maxHeight);
var currentWidth = (currentHeight * this.rate).toFixed(0);
if (currentWidth > _maxWidth)
{//超宽
currentWidth = _maxWidth;
currentHeight = (currentWidth / this.rate).toFixed(0);
}
if (currentWidth < this.minWidth)
{//超窄
currentWidth = this.minWidth;
currentHeight = (currentWidth / this.rate).toFixed(0);
}
this.doPrivateCss({width: currentWidth, height: currentHeight});
},
setPosition:function(_left, _top)
{//指定位置
var _maxLeft = this.pWidth - this.$elem.offsetWidth(); //拖拽层相对父节点最大左位置
var _maxTop = this.pHeight - this.$elem.offsetHeight(); //拖拽层相对父节点最大上位置
var currentleft = Math.min(Math.max(_left, 0), _maxLeft);
var currentTop = Math.min(Math.max(_top, 0), _maxTop);
this.doPrivateCss({left: currentleft, top: currentTop});
},
setPositionPoint:function(_pos)
{//指定上下左右四个角
if (_pos != 2 && _pos != 3 && _pos != 4)
{
this.setPosition(0, 0);
return;
}
var _maxLeft = this.pWidth - this.$elem.offsetWidth(); //拖拽层相对父节点最大左位置
var _maxTop = this.pHeight - this.$elem.offsetHeight(); //拖拽层相对父节点最大上位置
switch(_pos)
{
case 2:this.setPosition(_maxLeft, 0);break;
case 3:this.setPosition(0, _maxTop);break;
case 4:this.setPosition(_maxLeft, _maxTop);break;
}
},
/*******************************************************/
//以下为键盘操作属性
/*******************************************************/
doLeft:function()
{//左
var currentLeft = Math.max(this.$border.offsetLeft()-1, 0);
this.doPrivateCss({left: (currentLeft)+"px"});
this.doPrivateCallback("onLeft");
},
doUp:function()
{//上
var currentTop = Math.max(this.$border.offsetTop()-1, 0);
this.doPrivateCss({top: currentTop});
this.doPrivateCallback("onUp");
},
doRight:function()
{//右
var _maxLeft = this.pWidth - this.$border.offsetWidth(); //拖拽层相对父节点最大左位置
var currentleft = Math.min(this.$border.offsetLeft()+1, _maxLeft);
this.doPrivateCss({left: currentleft});
this.doPrivateCallback("onRight");
},
doDown:function()
{//下
var _maxTop = this.pHeight - this.$border.offsetHeight(); //拖拽层相对父节点最大上位置
var currentTop = Math.min(this.$border.offsetTop()+1, _maxTop);
this.doPrivateCss({top: currentTop});
this.doPrivateCallback("onDown");
},
doWidthIncrease:function()
{//加宽
var _maxWidth = this.pWidth - this.$border.offsetLeft();
var currentWidth = Math.min(this.$border.offsetWidth()+1, _maxWidth);
this.doPrivateCss({width: currentWidth});
this.doPrivateCallback("onWidthIncrease");
},
doWidthDecrease:function()
{//减宽
var currentWidth = Math.max(this.$border.offsetWidth()-1, this.minWidth);
this.doPrivateCss({width: currentWidth});
this.doPrivateCallback("onWidthDecrease");
},
doHeightIncrease:function()
{//加高
var _maxHeight = this.pHeight - this.$border.offsetTop();
var currentHeight = Math.min(this.$border.offsetHeight()+1, _maxHeight);
this.doPrivateCss({height: currentHeight});
this.doPrivateCallback("onHeightIncrease");
},
doHeightDecrease:function()
{//减高
var currentHeight = Math.max(this.$border.offsetHeight()-1, this.minHeight);
this.doPrivateCss({height: currentHeight});
this.doPrivateCallback("onHeightDecrease");
},
/*******************************************************/
//以下为鼠标事件属性
/*******************************************************/
doMouseOver:function(e)
{//鼠标移入,选中并建立鼠标移动事件,显示拖动和缩放不同的鼠标样式
if (this.cursor != null)
{//鼠标已按下,由于拖动或缩放时出现移入移出事件不处理
return;
}
this.$border.mousemove(this.doMouseMove, this);
this.doPrivateCallback("onMouseOver");
},
doMouseOut:function(e)
{//鼠标移出,恢复未选中状态
if (this.cursor != null)
{//鼠标已按下,由于拖动或缩放时出现移入移出事件不处理
return;
}
this.doPrivateCallback("onMouseOut");
},
doMouseMove:function(e)
{//鼠标移动,根据鼠标位置显示拖动和缩放不同的鼠标样式
this.bordered();
this.$border.css("cursor", this.doPrivateCursor(e));
},
doMouseDown:function(e)
{//鼠标按下,关闭鼠标移动显示鼠标样式事件,开启拖动还是缩放事件
this.$border.offmousemove(this.doMouseMove, this);
this.cursor = this.doPrivateCursor(e);
this.$border.css("cursor", this.cursor);
var clientX = Z.E.clientX(e);
var clientY = Z.E.clientY(e);
if (this.cursor == "move")
{
this.moveStartX = clientX - this.$border.offsetLeft();
this.moveStartY = clientY - this.$border.offsetTop();
Z(document).mousemove(this.doDrag, this);
}
else
{
this.resizeStartX = clientX - this.$border.offsetWidth();
this.resizeStartY = clientY - this.$border.offsetHeight();
Z(document).mousemove(this.doResize, this);
}
//开启全文档鼠标松开释放事件
Z(document).mouseup(this.doMouseUp, this);
//停止冒泡和阻止缺省事件
Z.E.forbidden(e);
this.doPrivateCallback("onMouseDown");
},
doMouseUp:function(e)
{//鼠标释放
Z(document).offmouseup(this.doMouseUp, this);
Z(document).offmousemove(this.doDrag, this);
Z(document).offmousemove(this.doResize, this);
//恢复默认移动
this.cursor = null;
this.$border.mousemove(this.doMouseMove, this);
this.doPrivateCallback("onMouseUp");
},
doDrag:function(e)
{//拖动
var clientX = Z.E.clientX(e);
var clientY = Z.E.clientY(e);
this.setPosition(clientX - this.moveStartX, clientY - this.moveStartY);
this.doPrivateCallback("onDrag");
},
doResize: function(e)
{//缩放,共三种情况,左右缩放,上下缩放,斜向缩放(固定和不固定比例)
var clientX = Z.E.clientX(e);
var clientY = Z.E.clientY(e);
//控制在父层内放大,最小20像素
var _maxWidth = this.pWidth - this.$border.offsetLeft();
var _maxHeight = this.pHeight - this.$border.offsetTop();
var currentWidth = Math.max(clientX - this.resizeStartX, this.minWidth);
var currentHeight = Math.max(clientY - this.resizeStartY, this.minHeight);
if (this.cursor == "e-resize")
{//左右缩放,只变宽
this.doPrivateCss({width: Math.min(currentWidth, _maxWidth)});
}
else if (this.cursor == "n-resize")
{//上下缩放,只变高
this.doPrivateCss({height: Math.min(currentHeight, _maxHeight)});
}
else if (this.cursor == "nw-resize")
{//斜向缩放(固定和不固定比例)
currentWidth = Math.min(currentWidth, _maxWidth);
currentHeight = Math.min(currentHeight, _maxHeight);
if (this.isResizeRate)
{//固定比例时,要求两值都必须要最小最大之间
var wh = this.doPrivateResizeRate(currentWidth, currentHeight, _maxWidth, _maxHeight);
currentWidth = wh[0];
currentHeight = wh[1];
}
this.doPrivateCss({width: currentWidth, height: currentHeight});
}
this.doPrivateCallback("onResize");
},
/*******************************************************/
//以下为内部私有方法
/*******************************************************/
doPrivateResizeRate: function(currentWidth, currentHeight, _maxWidth, _maxHeight)
{//按比例计算新的宽高
if (!this.isResizeRate)
return [currentWidth, currentHeight];
var _maxRate = _maxWidth / _maxHeight;
if (this.rate > _maxRate)
{//图片比例 大于 能拉伸的最大比例时,表明宽先到达边界,则高以宽为基准作比较缩放
currentHeight = (currentWidth / this.rate).toFixed(0);
if (currentHeight < this.minHeight)
{
var tempWidth = (this.minHeight * this.rate).toFixed(0);
if (tempWidth < _maxWidth)
{//当高小于最小值,反算宽小于最大值时,取高最小值
currentHeight = this.minHeight;
currentWidth = tempWidth;
}
}
}
else
{//否则宽以高为基准作比较缩放
currentWidth = (currentHeight * this.rate).toFixed(0);
if (currentWidth < this.minWidth)
{
var tempHeight = (this.minWidth / this.rate).toFixed(0);
if (tempHeight < _maxHeight)
{//当高小于最小值,反算宽小于最大值时,取高最小值
currentWidth = this.minWidth;
currentHeight = tempHeight;
}
}
}
return [currentWidth, currentHeight];
},
doPrivateCursor: function(e)
{//获取鼠标手势
var clientX = Z.E.clientX(e);
var clientY = Z.E.clientY(e);
//判断缩放还是移动
var maxX = this.$border.clientX()+this.$border.offsetWidth();
var maxY = this.$border.clientY()+this.$border.offsetHeight();
if (clientX > (maxX - this.cursorWidth) && clientY > (maxY - this.cursorHeight))
{//比例缩放(右下角)
return "nw-resize";
}
else if (!this.isResizeRate && clientX > (maxX - this.cursorWidth))
{//左右缩放
return "e-resize";
}
else if (!this.isResizeRate && clientY > (maxY - this.cursorHeight))
{//上下缩放
return "n-resize";
}
else
{//移动
return "move";
}
},
doPrivateCss: function(obj)
{//设置CSS
this.$elem.css(obj);
this.$border.css(obj);
},
doPrivateCallback: function(on)
{//回调
if (Z.T.isFunction(this.callback)){
this.callback(this, on);
}
}
}
//END
})(zhiqim);