一共涉及到以下几个功能:
1、按照鼠标中心点进行缩放
2、四个角允许拖动
3、盒子的拖拽
4、图片拖拽
5、增加放大镜
6、图片默认展示
1、按照鼠标中心点进行缩放
操作:鼠标放置在图区中,滚轮滚动
现象:以鼠标中的点进行,缩放。
思路:滚轮缩放, 通过 捕获 事件对象的步长。然后通过 transfrom scale 实现缩放。缩放平移,在视觉上达到中心点缩放的效果。
注意点: transfrom 所有属性都不改变元素的布局。scale 只会引起重绘,不会引起重排。在性能上 scale 会更高。如果想让图片真正的变化。可以使用zoom。在这里我们使用的是 transfrom。 需要值得注意的是, 图片的一系列 offset 属性就不能用。offset系列全部都是相对于真正的图片的计算。
这里可以多说一点: 为什么scale 不会引起重排呢? 这个和浏览器的渲染引擎有关系。可以看一下v8引擎。 这块渲染的时候,就像是 照相机调焦距一样。所以他的computed里面的数值是不变的。所以性能会更高。
2、四个角允许拖动
操作:鼠标点击盒子的四个角。然后拉伸拖拽。
现象:盒子会根据拖动方向进行变化。
思路:
拖动四个角的时候,图片长和宽都是可能是要变化的。
拖动左下角的时候,left 和 bottom 也是要变化的。
拖动左上角的时候,left 和 top 也是要变化的。
拖动右下角的时候,right 和 bottom 也会要变化的。
拖动右上角的时候,right 和 top 是要跟着变化的。
注意点: 需要注意的是,这里会有默认值。left right top bottom 是用来限定盒子位置的。
默认bottom 和 right 是不需要写的。 当固定住 left 和 top的值,跟着变化长和宽就可以了。
因此:
拖动左下角的时候,left 变化的。
拖动左上角的时候,left 和top 也是要变化的。
拖动右下角的时候,不需要设置位置。
拖动右上角的时候,top 是要跟着变化的。
3、盒子的拖拽
操作:鼠标点击的盒子,然后进行拖拽。
现象:盒子会根绝拖动的方向进行变化。
4、图片拖拽
操作:鼠标点击图片,然后进行拖拽。
现象:图片会根据拖拽的方向进行移动。
5、增加放大镜
操作:鼠标右键点击图片,放大镜就会开启,移动鼠标。
现象:放大镜开启偶,会根据鼠标的内容,进行放大。
6、图片默认展示
操作: 点击 图标,开启 盒子。
现象:首次进入。会默认进行筛选。有 图片的选项,并展示。
功能糅杂:
1/ 中心点缩放代码:
// 图片鼠标滚轮
handleWheel(e) {
const step = e.wheelDeltaY > 0 ? this.step : -this.step;
this.cur = Number(this.cur.toFixed(1)) + step;
// 滚轮标志位
this.fitFlag = false;
if (this.cur >= this.max) {
this.cur = this.max;
} else if (this.cur <= this.min) {
this.cur = this.min;
}
this.scale(this.cur, e);
},
// 图片缩放比例
scale(scale, e) {
if (e) {
// 主要计算 当图片 用鼠标滚轮 缩放 拖拽 后的 的比例
const pDom = this.$refs.imgUrl.parentElement;
// 返回元素的大小及其相对于视口的位置
const { top: pTop, left: pLeft } = pDom.getBoundingClientRect();
// 返回图片的大小及其相对于视口的位置
const { height, width } = this.$refs.imgUrl.getBoundingClientRect();
// 获取比例
let yScale, xScale;
// this.left 和 this.top 存一下 当变化了。查看变化了多少
yScale = (e.pageY - pTop - this.prevTranslateMap.y - this.top) / height;
xScale = (e.pageX - pLeft - this.prevTranslateMap.x - this.left) / width;
// 变化后的 长度 宽度
const ampHeight = scale * this.initHeight;
const ampWidth = scale * this.initWidth;
// 需要重新运算的 translate 坐标 放大缩小后 对应的 translate 是变化的
const y = yScale * (ampHeight - height);
const x = xScale * (ampWidth - width);
const translateY = this.prevTranslateMap.y - y;
const translateX = this.prevTranslateMap.x - x;
this.bodyStyle.transform = `translate(${translateX}px, ${translateY}px) scale(${scale})`;
// 记录这次偏移的值
this.prevTranslateMap = {
x: translateX,
y: translateY
};
// 记录这次left top的值
this.prevDragMap = {
x: this.left,
y: this.top
};
} else {
// body 是绑定在图片上的
this.bodyStyle.transform = `translate(${this.prevTranslateMap.x}px, ${this.prevTranslateMap.y}px) scale(${scale})`;
}
},
实现:
中心点缩放, 首先通过鼠标滚动,获得 是正的还是负的。 是正的 步长加 0.1。 是负的 。 步长减0.1。
this.cur = Number(this.cur.toFixed(1)) + step;
由于四个角拉伸也用到 this.cur了。 并且为了让图片平滑移动。 this.cur 是不规则的小数。 而鼠标滚动式 按照步长 增长减少。
所以在这里保留一位小数。变化。
这里边界值判断, 判断是否达到最大 缩放值。达到之后不允许放大。如果小于最小缩放值,不允许缩小。
缩放的方法:
由于鼠标滚动的缩放是中心点缩放。 所以需要用到 事件对象的。 而拉动四个角是不需要 事件对象的。
当有事件对象的时候,
// this.left 和 this.top 存一下 当变化了。查看变化了多少
yScale = (e.pageY - pTop - this.prevTranslateMap.y - this.top) / height;
xScale = (e.pageX - pLeft - this.prevTranslateMap.x - this.left) / width;
这里详细讲一下: this.prevTranslateMap.y 是存着上次transfrom 的偏移量。
this.prevDragmap 存着 left 和 top 的值。 是给 图片拖拽的方法存的。 可直接看 图片的拖拽方法。
图片的拖拽方法:
// 图片的拖拽 dragBox 是图片本身
drag(dragBox) {
dragBox.onmousedown = (e) => {
const Pdom = dragBox.parentElement.getBoundingClientRect();
const dom = dragBox.getBoundingClientRect();
// 盒子的左边界
const minLeft = Pdom.left - dom.left;
// 盒子的右边界 点都是 左上角
const maxLeft = Pdom.right - dom.right;
// 盒子的上边界
const minTop = Pdom.top - dom.top;
// 盒子的下边界
const maxTop = Pdom.bottom - dom.bottom;
const disX = e.clientX;
const disY = e.clientY;
// 遇到图片缩小,拖拽到盒子边界,然后放大。
this.imgMove(dragBox, minLeft, maxLeft, minTop, maxTop);
document.onmousemove = (e) => {
e.preventDefault();
this.left = e.clientX - disX + this.prevDragMap.x;
this.top = e.clientY - disY + this.prevDragMap.y;
this.imgMove(dragBox, minLeft, maxLeft, minTop, maxTop);
return false;
};
document.onmouseup = () => {
document.onmousemove = null;
document.onmouseup = null;
// 记录这次的值
this.prevDragMap = {
x: this.left,
y: this.top
};
return false;
};
return false;
};
},
// 图片移动
imgMove(dragBox, minLeft, maxLeft, minTop, maxTop) {
this.isOutrideBorder(minLeft, maxLeft, minTop, maxTop);
dragBox.style.left = this.left + 'px';
dragBox.style.top = this.top + 'px';
},
// 边界判断
isOutrideBorder(minLeft, maxLeft, minTop, maxTop) {
if (this.cur <= this.scaleW) {
// 这里原理是 缩放后的位置 this.left 加上上一次的left
if (this.left <= minLeft + this.prevDragMap.x) {
this.left = minLeft + this.prevDragMap.x;
} else if (this.left >= maxLeft + this.prevDragMap.x) {
this.left = maxLeft + this.prevDragMap.x;
}
}
if (this.cur <= this.scaleH) {
if (this.top < minTop + this.prevDragMap.y) {
this.top = minTop + this.prevDragMap.y;
} else if (this.top > maxTop + this.prevDragMap.y) {
this.top = maxTop + this.prevDragMap.y;
}
}
// 处理由于是宽图片,恰好在最大值和 最小值之间徘徊。
if (this.cur > this.scaleW && this.cur < this.scaleW + 0.1) {
this.left = this.prevDragMap.x;
}
if (this.cur >= this.scaleW + 0.1) {
if (this.left > minLeft + this.prevDragMap.x) {
this.left = minLeft + this.prevDragMap.x;
} else if (this.left < maxLeft + this.prevDragMap.x) {
this.left = maxLeft + this.prevDragMap.x;
}
}
if (this.cur > this.scaleH) {
if (this.top < maxTop + this.prevDragMap.y) {
// 向上拉动
this.top = maxTop + this.prevDragMap.y;
} else if (this.top > minTop + this.prevDragMap.y) {
// 向下滑动
this.top = minTop + this.prevDragMap.y;
}
}
},
图片拖拽的边界 逻辑:
补充一个方法 getBoundingClientRect
dragBox 是图片本身。 offset 一系列都是不能使用的。
用这个已经计算出来的方法。
// 盒子的左边界
const minLeft = Pdom.left - dom.left;
// 盒子的右边界 点都是 左上角
const maxLeft = Pdom.right - dom.right;
// 盒子的上边界
const minTop = Pdom.top - dom.top;
// 盒子的下边界
const maxTop = Pdom.bottom - dom.bottom;
( 图片盒子减去图片的left值 )。 允许移动最小的 left 值。 这些值都是相对于 视口的左上角的。
right 也是相对于视口的边界局的。 也就是说 图片和 盒子的 右边界 相对于视口左上角的距离。
同理, top 就是上边界 相对于视口。 bottom 是和图片 和字的 bottom 相对于视口上边的距离。
鼠标点击下的时候, 需要给图片位置归正。
因为。如果不归正的的话。拖拽不平滑。会有一个跳动。 所以 跳动放在了 鼠标按下的瞬间。
// 遇到图片缩小,拖拽到盒子边界,然后放大。
this.imgMove(dragBox, minLeft, maxLeft, minTop, maxTop);
移动的逻辑, 在鼠标点下的时候,获得事件对象的点信息, 然后在获得移动的 鼠标的点的事件对象信息。通过差值。 得到移动的距离
this.left = e.clientX - disX + this.prevDragMap.x;
this.top = e.clientY - disY + this.prevDragMap.y;
拖拽图片,图片要移动,但是图片上次移动过的 left、top。 需要保留。
如果不保留的话,图片还是会跳动的。 保留的方法,放到了 鼠标抬起事件上。
这里的边界值判断:
// 边界判断
isOutrideBorder(minLeft, maxLeft, minTop, maxTop) {
if (this.cur <= this.scaleW) {
// 这里原理是 缩放后的位置 this.left 加上上一次的left
if (this.left <= minLeft + this.prevDragMap.x) {
this.left = minLeft + this.prevDragMap.x;
} else if (this.left >= maxLeft + this.prevDragMap.x) {
this.left = maxLeft + this.prevDragMap.x;
}
}
if (this.cur <= this.scaleH) {
if (this.top < minTop + this.prevDragMap.y) {
this.top = minTop + this.prevDragMap.y;
} else if (this.top > maxTop + this.prevDragMap.y) {
this.top = maxTop + this.prevDragMap.y;
}
}
if (this.cur > this.scaleW) {
if (this.left > minLeft + this.prevDragMap.x) {
this.left = minLeft + this.prevDragMap.x;
} else if (this.left < maxLeft + this.prevDragMap.x) {
this.left = maxLeft + this.prevDragMap.x;
}
}
if (this.cur > this.scaleH) {
if (this.top < maxTop + this.prevDragMap.y) {
// 向上拉动
this.top = maxTop + this.prevDragMap.y;
} else if (this.top > minTop + this.prevDragMap.y) {
// 向下滑动
this.top = minTop + this.prevDragMap.y;
}
}
图片移动的边界,也是需要分成两个, 还是因为 四个角拖拽是 不规则的。
当图片的比例小于或者 等于 盒子水平 缩放比例的时候。
判断逻辑为:
图片移动的距离 - 上次移动的距离 = 这次真实的移动距离
真实的移动距离 与 (允许的最小移动)距离进行判别。
当图片比例大于 盒子比例同样可以使用这个。 因为都是 用的盒子的 left 减去 图片的left。
2、 拖动四个角的时候。图片跟随变化的情况。
// 四个角的拉动
scales(dragBox, moveBox = dragBox, context) {
let that = this;
dragBox.onmousedown = function(e) {
let oEvent = e || event;
var dragStartWidth = moveBox.offsetWidth;
var dragStartHeight = moveBox.offsetHeight;
let mouseStartx = oEvent.clientX;
let mouseStarty = oEvent.clientY;
let img = document.getElementById('img');
// imgcontainer 获取图片的父元素
const imgParent = document.getElementsByClassName('imgcontainer')[0];
// 当图片在框子内的时候,点击四个角的点时,left translate 都重置为0
let x = Number(that.prevTranslateMap.x.toFixed(2)) + Number(that.left.toFixed(2));
let y = Number(that.prevTranslateMap.y.toFixed(2)) + Number(that.top.toFixed(2));
if ((x >= 0) && (y >= 0)) {
that.resetImg();
}
// 获得页面的宽 document.body.clientWidth
let maxWidth = document.body.clientWidth - imgParent.offsetParent.offsetLeft;
// 判断 放大镜图区是否出现了
if (that.clickCrowFlag) {
maxWidth = document.body.clientWidth - imgParent.offsetParent.offsetLeft - that.rightDis;
}
document.onmousemove = function (ev) {
let oEvent = ev || event;
let w, h;
// 偏移量
let l = oEvent.clientX - mouseStartx;
let t = oEvent.clientY - mouseStarty;
let left = oEvent.clientX;
let flag;
const { height, width } = that.$refs.imgUrl.getBoundingClientRect();
switch(dragBox.id) {
case('dlg_right_bottom'):
w = dragStartWidth + l;
h = dragStartHeight + t;
w = that.fourBorder(w, h, maxWidth).w;
h = that.fourBorder(w, h, maxWidth).h;
break;
case('dlg_right_top'):
w = dragStartWidth + l;
h = dragStartHeight - t;
// 达到边界的时候,left top 也不允许移动
flag = that.fourBorder(w, h, maxWidth);
w = flag.w;
h = flag.h;
if (flag.fourBorderFlagH) {
moveBox.style.top = oEvent.clientY + 'px';
}
break;
case('dlg_left_top'):
w = dragStartWidth - l;
h = dragStartHeight - t;
flag = that.fourBorder(w, h, maxWidth);
w = flag.w;
h = flag.h;
// 如果没有达到边界
if (flag.fourBorderFlagW) {
moveBox.style.left = left + 'px';
}
if (flag.fourBorderFlagH) {
moveBox.style.top = oEvent.clientY + 'px';
}
break;
case('dlg_left_bottom'):
w = dragStartWidth - l;
h = dragStartHeight + t;
flag = that.fourBorder(w, h, maxWidth);
w = flag.w;
h = flag.h;
if (flag.fourBorderFlagW) {
moveBox.style.left = left + 'px';
}
break;
}
that.scaleW = (w - 50) / that.initWidth;
that.scaleH = (h - 210) / that.initHeight;
// 图片缩放
that.picScale();
moveBox.style.width = w + "px";
moveBox.style.height = h + "px";
// computed 800-750 盒子的宽减去图片的宽
imgParent.style.width = (w - 50) + "px";
// computed 630-420 盒子的高减去图片的高
imgParent.style.height = (h - 210) + "px";
};
document.onmouseup = function (ev) {
document.onmousemove = null;
document.onmouseup = null;
return false;
};
return false;
}
},
逻辑:
1、先得到宽度的长和宽。然后拉动四个角。得到移动的 长 和 高。
增加一步判别。 如果图片在盒子里面的时候。点击下四个角的任意一个。 让图片贴合在左上角。
这里,想做的功能是。 如果图片小于盒子。 图片要随着盒子变化而变化。 只有坐上角贴合才不会出现问题。
2、用 点击时候的长和高加上 移动的长和高。得到拖拽四个角之后盒子的大小。
这里需要增加判断。放大镜区域是否开启。如果开启的话。 右上和右下角的拖拽就应该是 页面大小 - 放大镜区域的大小。
没有没有开启。 右上角和 右下角拖拽 就是 页面的 大小。
此时就需要用到下面的 四个角边界判断。
3、四个角边界判断
// 拉伸四个角的边界
fourBorder(w, h, maxWidth) {
let fourBorderFlagW = true, fourBorderFlagH = true;
if (w < this.leastWidth) {
w = this.leastWidth;
fourBorderFlagW = false;
}
if (maxWidth && w > maxWidth) {
w = maxWidth;
fourBorderFlagW = false;
}
if (h < 434) {
h = 434;
fourBorderFlagH = false;
}
const Border = {
w, h, fourBorderFlagW, fourBorderFlagH
}
return Border;
},
两个标志位: fourBorderFlagW 宽度极值。 fourBorderFlagH高度极值。
这里判断,如果当前宽度小于 this.leastWidth。this.leastWidth是我们设置的最小值。 this.leastWidth初始化的时候 是 600;
为什么要用600呢。 只有600的时候,两行筛选项 才不会串行。
当宽度小于 600 或者 宽度大于 页面允许的最大宽度的时候, fourBorderFlagW 为false。 表示开启极值边界。
同理高度也是一样。 将计算好的宽度高度和是否达到边界的极值返回。
四个角的拉伸边界判断
switch(dragBox.id) {
case('dlg_right_bottom'):
w = dragStartWidth + l;
h = dragStartHeight + t;
w = that.fourBorder(w, h, maxWidth).w;
h = that.fourBorder(w, h, maxWidth).h;
break;
case('dlg_right_top'):
w = dragStartWidth + l;
h = dragStartHeight - t;
// 达到边界的时候,left top 也不允许移动
flag = that.fourBorder(w, h, maxWidth);
w = flag.w;
h = flag.h;
if (flag.fourBorderFlagH) {
moveBox.style.top = oEvent.clientY + 'px';
}
break;
case('dlg_left_top'):
w = dragStartWidth - l;
h = dragStartHeight - t;
flag = that.fourBorder(w, h, maxWidth);
w = flag.w;
h = flag.h;
// 如果没有达到边界
if (flag.fourBorderFlagW) {
moveBox.style.left = left + 'px';
}
if (flag.fourBorderFlagH) {
moveBox.style.top = oEvent.clientY + 'px';
}
break;
case('dlg_left_bottom'):
w = dragStartWidth - l;
h = dragStartHeight + t;
flag = that.fourBorder(w, h, maxWidth);
w = flag.w;
h = flag.h;
if (flag.fourBorderFlagW) {
moveBox.style.left = left + 'px';
}
break;
}
逻辑:
通过边界方法得到真正的可以变化的宽度和高度。 右边直接变化宽度和高度即可。 但是左边不一样。 拉动左边。 盒子的left top 是要跟随变化。
为什么要变化呢。 只有变化,才能在视觉上达到 拉伸角盒子变化的效果。
这个时候边界标志位就有作用了。 当最小的时候, left 不允许变化。 宽度和 高度 也不是不允许变化的。
这里面会有一个小问题, 当达到最小值的时候。松开鼠标,再次拖动 左上角 和 左下角。 会有一点点的偏移。 TODO
盒子允许缩放的值: 为什么要有盒子允许图片缩放的值呢 ?
由于拖动四个角是不规则的, 可以任意拉伸。例如。 直的向下,直的向右。
我们需要得到 长和宽, 自己的变化比例。 然后取变化比例 最小的值, 给与 图片。
计算 得到图片变化的比例
// computed 800-750 盒子的宽减去图片的宽
that.scaleW = (w - 50) / that.initWidth;
// computed 632-420 盒子的高减去图片的高
that.scaleH = (h - 212) / that.initHeight;
逻辑是:
1、当图片 在 盒子的外面。 拖动四个角,图片就不允许跟随缩放。
(图片出现在盒子外面的情况。 使用滚轮 实现 图片放大。 )
3、 图片缩放的方法
为了保证 滚轮滚动的时候,能准确的控制图片的缩放。同时为了保证,拉伸四个角的时候,是平滑缩放。
由于 鼠标滚动是 0.1 的倍数。 所以在 拖动四个角的是,不适用 toFixed(1) 。 当鼠标滚动的时候, toFixed(1)。 保留一位小数进行计算。
变化条件的逻辑是:
当图片缩放比例 小于盒子允许最小值的时候。并且贴合边界。此时拖动。就会跟随变化。
点击四个角的时候,判断图片的缩放是否小于 盒子的允许图片缩放的最小值。
// 图片缩放
picScale() {
let scaleW = this.scaleW;
let scaleH = this.scaleH;
let scaleNum = 1;
// 取得最小的缩放值
this.proportion = Number(scaleW) > Number(scaleH) ? Number(scaleH) : Number(scaleW);
this.scaleW = Number(scaleW);
this.scaleH = Number(scaleH);
let x = Number(this.prevTranslateMap.x.toFixed(2)) + Number(this.left.toFixed(2));
let y = Number(this.prevTranslateMap.y.toFixed(2)) + Number(this.top.toFixed(2));
// 图片在 盒子外面, 不缩放
if ((x < 0) || (y < 0)) {
return;
}
// fitFlag 是否贴合标志位
if (!this.fitFlag) {
// 贴合判断条件 this.proportion 是很多位小数的。为了平滑缩放
// this.cur 是按照 0.1 倍数增长,0.1是步长
if(+(this.proportion.toFixed(1)) === +(this.cur.toFixed(1))) {
this.fitFlag = true;
}
}
if (this.fitFlag) {
this.cur = this.proportion;
}
this.scale(this.cur);
},
策略是:
当图片如果在盒子外面, 图片缩放比例大于盒子。 不允许进行缩放。
但是浏览器处理的小数会精度不足。 所以这里在判断的时候, 去小数位 后两位。 toFixed(2) 方法 toFixed方法得到的结果。
默认是 字符串类型的。 这里使用Number() 转换了一下。
当不在图片不在盒子外面的时候, 需要判断 图片缩放比例是否和 盒子缩放比例一致。 如果一致的话, 再次拖动四个角, 图片要跟随盒子进行变化。
3、放大镜的移动方法,边界限制
// 移动的方法 放大镜模块
move(boxCrow, smallBox, BigCrowMove, dragBox) {
// 右键的事件
boxCrow.oncontextmenu = (e) => {
e.preventDefault();
// 鼠标所在位置在不在图片区域内
if (this.clickCrowFlag === false) {
this.clickCrowFlag = this.isPicContent(e, boxCrow);
} else {
// 右键关闭
this.clickCrowFlag = false;
}
// 如果这个时候没有开启 直接返回 以下代码不执行
if (this.clickCrowFlag === false) {
return;
}
const Pdom = dragBox.parentElement.getBoundingClientRect();
const dom = dragBox.getBoundingClientRect();
const x = document.documentElement.clientWidth - this.$refs.dialog.offsetWidth - this.rightDis;
const dialogLeft = this.$refs.dialog.style.left ? this.$refs.dialog.style.left : x + 'px';
if (dialogLeft.substring(0, dialogLeft.length - 2) >= x) {
this.$refs.dialog.style.left = x + 'px';
}
// 盒子的左边界
const minLeft = Pdom.left - dom.left;
// 盒子的右边界
const maxLeft = Pdom.right - dom.right;
// 盒子的上边界
const minTop = Pdom.top - dom.top;
// 盒子的下边界
const maxTop = Pdom.bottom - dom.bottom;
// 放大镜选中框边界限制
this.isSmailOutrideBorder(e, boxCrow, smallBox, BigCrowMove);
// 图片位置纠正
this.imgMove(dragBox, minLeft, maxLeft, minTop, maxTop);
// 当右键点击下后, magnifyingImg 尺寸发生变化, 要是缩放图片的2倍
this.getMagnifyingImg();
boxCrow.onmousemove = (e) => {
e.preventDefault();
this.isSmailOutrideBorder(e, boxCrow, smallBox, BigCrowMove);
};
return false;
};
},
1、放大镜开启放在鼠标右键点击上:
由于拖拽事件,是在鼠标按下的事件。如果放大镜放在移入或者鼠标按下开启,那么拖拽事件就不能使用了。
因此, 放大镜事件,放在了鼠标右击的事件上。 右击开启放大镜。
2、右键点击之后,进入判断 放大镜的标志位置是否开启,如果没有开启,进行判断 点击的点 是否在图片上。如果再图片上,开启放大镜。如果不在直接return。以下代码不执行。
3、 当在图片上的时候。 会开启放大镜,此时放大镜的窗口显示。
放大镜窗口显示位置 要求 放大镜窗口的左边界贴合 弹窗的右边界。
因此,需要判断 弹窗相对对于屏幕视图窗口右边的距离是否小于 放大镜窗口的宽度。
但是, 右边界无法判断,因此使用left 值。
const Pdom = dragBox.parentElement.getBoundingClientRect();
const dom = dragBox.getBoundingClientRect();
const x = document.documentElement.clientWidth - this.$refs.dialog.offsetWidth - this.rightDis;
const dialogLeft = this.$refs.dialog.style.left ? this.$refs.dialog.style.left : x + 'px';
if (dialogLeft.substring(0, dialogLeft.length - 2) >= x) {
this.$refs.dialog.style.left = x + 'px';
}
视口的宽度 - 盒子的宽度 - 放大镜盒子的宽度 = x。 这个x 就是允许放大的值。
这里多判断一步。 因为首次进入页面, 页面style.left 是不存在的。 x 是 值类型, 而 left 是 带有 'px’的 字符串类型。 然后进行 统一。 先拼接px 。 然后切割。 得到 该存在的位置。
4、执行放大镜选中框 边界限制。
由于,放大镜选中框。 是通过 v-if 展示的。 首次开启。鼠标的点不会位于 展示框的中心点, 会位置 左上角。渲染是通过 左上角的点开始渲染的。
5、执行图片位置纠正
当图片缩小很小的很,然后放大,图片没有完全进入盒子。
纠正后:
6、放大镜边界限制
// 放大镜选中内容边界限制
isSmailOutrideBorder(e, boxCrow, smallBox, BigCrowMove) {
// 当前的宽度
const nowWidth = this.initWidth * this.cur;
const nowHeight = this.initHeight * this.cur;
// 图片小于盒子的时候。 边界 用 0;
this.move_left = e.clientX - boxCrow.offsetParent.offsetLeft - boxCrow.offsetLeft - this.smallWidth / 2;
this.move_top = e.clientY - boxCrow.offsetParent.offsetTop - boxCrow.offsetTop - this.smallHeight / 2;
// 当图片 大于 盒子
if (this.cur > this.scaleW){
// 此时的边界 为 盒子 直接用红边框盒子的宽 - 红色盒子的 宽
if (this.move_left < 0) {
this.move_left = 0;
} else if (this.move_left > boxCrow.offsetWidth - this.smallWidth) {
this.move_left = boxCrow.offsetWidth - this.smallWidth;
}
} else {
// 此时的边界 为图片
if (this.move_left < this.left + this.prevTranslateMap.x) {
this.move_left = this.left + this.prevTranslateMap.x;
} else if (this.move_left > nowWidth - this.smallWidth + this.left + this.prevTranslateMap.x) {
this.move_left = nowWidth - this.smallWidth + this.left + this.prevTranslateMap.x;
}
}
if (this.cur > this.scaleH) {
if (this.move_top < 0) {
this.move_top = 0;
} else if (this.move_top > boxCrow.offsetHeight - this.smallHeight) {
this.move_top = boxCrow.offsetHeight - this.smallHeight;
}
} else {
if (this.move_top < this.top + this.prevTranslateMap.y) {
this.move_top = this.top + this.prevTranslateMap.y;
} else if (this.move_top > nowHeight - this.smallHeight + this.top + this.prevTranslateMap.y) {
this.move_top = nowHeight - this.smallHeight + this.top + this.prevTranslateMap.y;
}
}
smallBox.style.left = this.move_left + 'px';
smallBox.style.top = this.move_top + 'px';
BigCrowMove.style.left = -(this.move_left - this.left - this.prevTranslateMap.x) * 2 + 'px';
BigCrowMove.style.top = -(this.move_top - this.top - this.prevTranslateMap.y) * 2 + 'px';
},
这里的判断逻辑是:
总逻辑是:
1、 判断图片缩放 是否大于 盒子的 宽缩放的比例, 如果大于 宽缩放的比例。 那就按照图片的宽度进行限制。
如果图片缩放 小于 盒子的宽 缩放的比例。就按照图片的宽度进行限制。
move_left 是 放大镜区域左边界 相距 图片盒子左边距的 距离。
鼠标当前的点 - 图片盒子相对于左边的距离 - 图片的父元素( 盒子)相对于左边的距离 - 放大镜区域大小的一半(为了在放大镜的中心)。
move_left 代表红色箭头的距离。
move_top 是 放大镜区域上边界 相距 图片盒子上边距的 距离
如果 红色箭头小于0。红色箭头为0。如果红色箭头大于 图片的宽度减去 放大镜区域的宽度。红色箭头长度为。 图片的宽度 减去放大镜区域的宽度。
当: 图片的宽的放大比例 小于 盒子的宽度的放大比例。
需要使用图片的 此时的比例的真实图片大小作为边界。
this.left 是图片的左边距。 this.prevTranslateMap.x 是鼠标滚动保存的偏移值。
因为图片小于图片盒子 的时候, 是可以拖拽的。 图片边界也要跟着变化。 用 this.left 和 this.pervTranslateMap.x 来作为边界进行计算。
注意: 当this.left 和 this.prevtranslateMap.x 都为 0 的时候,图片是靠在 图片盒子的左上角的。
因此这里我们可以用
最小值: this.left + this.prevtranslateMap.x 来进行边界的判断最小值。
最大值的话: 得用现在的宽度 - 放大镜区域的宽度
移动的距离 大于 现在图片的宽度 - 放大镜区域的宽度 则让 移动的移动为 现在图片的宽度 - 放大镜区域的宽度。
高度 思路一致。
首次点开 ,开启自动搜索
这里的实现是通过。 判断 时间和类型 是否在第一位。
this.radioTime === 1 && this.radioType === 1
如果第一位有图片。 直接展示。 如果第一位没有图片
// 当首次点击 显示的时候, 自动筛选
async getAutoCrowdImg()
const options = {
latLng: this.crowdImgLatLng,
startTime: this.crowdStartTime,
endTime: this.crowdEndTime,
radioType: this.radioType
};
let radioTypeArr = [1, 4, 2, 3];
for (let radioType of radioTypeArr) {
options.radioType = radioType;
// 时间范围数组
let arr = [1, 3, 6, 12];
for(let val of arr) {
this.timeSpilt(val);
options.startTime = this.crowdStartTime;
options.endTime = this.crowdEndTime;
const code = await this.getClickLatlng(options);
if (code.status === 0 && this.latlngList.length !== 0 ) {
this.aotoFlag = true;
this.radioTime = val;x
this.radioType = radioType;
return false;
}
}
}
},
开始遍历查询, 当查询到图片的时候, 将对应的节点信息,映射到 选筛项上。
多说一点。 需求想要开启放大镜的同时, 可以拖放图片,