中心点缩放,四个角允许拉伸添加放大镜等功能糅杂

一共涉及到以下几个功能:

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;
                    }
                }
            }
        },

开始遍历查询, 当查询到图片的时候, 将对应的节点信息,映射到 选筛项上。

多说一点。 需求想要开启放大镜的同时, 可以拖放图片,

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值