前言:这个制作纯属今天上课实在太无聊了瞎搞的······不过感觉想要的效果已经实现了~~~


先来看看实现的效果吧:

%e8%a3%81%e5%89%aa%e6%95%88%e6%9e%9c

我们可以看到左侧区域有一张图片,上面是很熟悉的区域选择矩形,右侧是实时预览区域(他的大小跟随框选区大小实时变化)。

然后我们来看一下上面效果的一些小细节:

1.框选区域上面的八个点连同整个区域都有各自不同的点击效果。

2.无论鼠标拖拽左侧框选区怎样移动都无法超出底面图片的边界。

3.无论左侧框选区怎样移动右侧的预览区域仅仅是大小和内容跟随移动,它的位置是固定的。

我们先来详细大体的制作方法:

1.怎样实现被选中区域比图片其他区域清晰明亮?

这个实现起来就得说说图层这个东西了,学过ps的同学应该都有对图层的了解,图层的作用就是将想要显示的东西沿着屏幕z轴叠加在一起达到你想要的效果,也就是说这个效果其实是两个图片位置重合的放在一起,在底部的图片我们可以设置其透明度小一些这就达到了视觉上与原图有明暗和清晰的区别,然后只需要截取靠上层的原图的一部分显示就可以了,因为两张图是位置重合的叠在一起所以就会感觉是在一张图片上挑选想要的区域。

2.怎样实现鼠标拖拽图片却不超出区域呢?

这就需要我们在拖拽的过程中计算边界,当鼠标移动距离转化为边长的变化后若边长已经超出边界时我们就只让其最大长度为框选区的八个点钟水平距离最远的点到其拖拽指向的那个边的距离。

3.怎样实现无论左侧框选区怎样移动右侧的预览区域仅仅是大小和内容跟随移动,它的位置是固定的呢?

其实右侧区域也是同左侧原图等大的一张图片,只不过只截取我们想要的区域显示了,至于它为什么可以位置固定我们可以这样想,鼠标每次移动都可以分为x轴和y轴两个方向的移动,当每次移动后都有一个偏移量,offsetX,offsetY,我们可以在固定点减去这两个偏移量就可以抵消图片的移动。

具体实现:

整体我们可以分为一个div中包裹着三层东西,最底层是一个图片它需要有不透明效果(opacity属性,可可以是0-1的任意一个浮点数,值越小越不透明),在它之上是同样一张图片位置与其重合没有不透明效果,最上层是带有八个点的框选区,框选区的制作很简单(使用clip属性来沿着框选区大小在原图层中截出一个矩形区域),就是一个div包裹八个小div并且每个小div具有背景颜色和大小,实现框选区有一个麻烦就是让其中的点分布均匀,所有的点需要沿着边界居中显示,右侧预览区是一个div包裹一个图片。

我们来看看具体代码:

1.关于不透明度以及对齐的样式:

<style type="text/css">
#imgBottom{
            position: absolute;
            top: 0px;;
            left: 0px;
            opacity: 0.3;/*设置不透明度*/
        }
.moveBox.leftUp{
            /*左上角*/
            position: absolute;
            left: 0px;
            top: -4px;
            margin-left: -4px;
            cursor: nw-resize;
        }

        .moveBox.leftMid{
            /*左边中间点*/
            position: absolute;
            left: 0px;
            top: 50%;
            margin-left: -4px;
            cursor: w-resize;
        }

        .moveBox.leftDown{
            /*左下角*/
            position: absolute;
            left: 0px;
            bottom: -4px;
            margin-left: -4px;
            cursor: sw-resize;

        }
</style>

2.具体布局:

<body>
    <div id="imgBox">
        <img src="james先生的logo.png" id="imgBottom">
        <img src="james先生的logo.png" id="imgTop">
        <div id="clipBox">

            <div class="moveBox leftUp" id="leftUp"></div>

            <div class="moveBox leftMid" id="leftMid"></div>

            <div class="moveBox leftDown" id="leftDown"></div >

            <div class="moveBox midUp" id="midUp"></div>

            <div class="moveBox midDown" id="midDown"></div>

            <div class="moveBox rightUp" id="rightUp"></div>

            <div class="moveBox rightMid" id="rightMid"></div>

            <div class="moveBox rightDown" id="rightDown"></div>

        </div>

    </div>

    <div id="preView">
        <img src="james先生的logo.png" id="imgView">
    </div>
</body>

3.关于鼠标拖拽以及距离限定详解:

说实话···搞这个鼠标拖动和距离限定花了我一个下午的时间,有没有很蠢···

先看个简单的当向右侧扩大拖拽的情况(鼠标向右拖动框选区右侧中间的点):

%e8%a3%81%e5%89%aa%e6%a8%a1%e5%9e%8b%e5%90%91%e5%8f%b3%e6%89%a9%e5%a4%a7

为什么说向右拖动扩大时比较简单呢,原因是横向拖动并不会改变框选区纵向的变化,而且也不会影响左边离屏幕的距离,因此就不会发生移动,我们只需关心右侧的参数变化就可以了。

上图中我们需要计算才能得出的是offsetX(鼠标拖动时出现的偏移量),currentWidth(实际扩大后的宽度),clipBoxX(框选区左边距离屏幕左边的距离),其他都是已知量,你们觉得上面那些未知量哪个好求?其实clipBoxX最好求,它的计算就是将每一层相对于父元素左边的左边距加起来直到无父元素为止。 来看看实现:

function getPosition(node) {

    /*offsetLeft获取该元素相对于父元素左边的距离,
    将多个相对的左边距加起来直到无父元素则加到边界,
    这时就可计算出该组件相对页面左边和顶部的距离*/

    var left=node.offsetLeft;
    var top=node.offsetTop;
    var parent=node.offsetParent;
    while(parent!=null)
    {
        left+=parent.offsetLeft;
        top+=parent.offsetTop;
        parent=parent.offsetParent;
    }

    return {"left":left,"top":top};
}

接下来就是来求一下偏移量,从上图很明显它的求出只需要这个公式:

offsetX = mouseX – clipBoxX – clipBoxWidth ;

当然同理实时长度也是公式可以得出:

currentwidth=boxOffsetX + clipBoxWidth;

因为要考虑边框所占像素,所以clipBoxWidth(裁剪区域宽度)应该比实际宽度少两个border的宽度, 因此currentwidth其实并不能像上面那样求,而是:

currentwidth=boxOffsetX + clipBoxWidth+2*border;

之后就是判断边界了,我的思路是使用currentwidth与 (imgBox_div.offsetWidth-clipBox_div.offsetLeft)的值进行对比,如果currentwidth大则超边界。来看实现:

var currentwidth=boxOffsetX + clipBoxWidth +2;//加回边框

        if((imgBox_div.offsetWidth-clipBox_div.offsetLeft)<currentwidth)
        {
            currentwidth=imgBox_div.offsetWidth-clipBox_div.offsetLeft +2;

        }
        clipBox_div.style.width = currentwidth + "px";

接着我们再来个麻烦点的鼠标拖动框选区上边中点向上拖动:

%e8%a3%81%e5%89%aa%e6%a8%a1%e5%9e%8b%e5%90%91%e4%b8%8a%e6%89%a9%e5%a4%a7

未知量与向右拖动基本一致,只是这次我们拖动上边时影响到了框选区的top值,而且top值也有区域限制必须在区域内因此得保证其为正值,因此实现的结果应该是当向上拖动时高度增加而top被减小,来看实现:

var upOffset=clipBox_div.offsetTop - boxOffsetY;

        upOffset=Math.max(0,upOffset);
        clipBox_div.style.top= upOffset + "px";
        if(upOffset!=0) {
            clipBox_div.style.height = boxOffsetY + clipBoxHeight + "px";
        }

其他两个方向的拖动实现效果类似因此不再赘述。还需要提一句的就是四个角上的拖动其实依然是分解为两个方向拖动的组合就好例如:

switch (divmark)
            { 
                    case "leftMid":
                    leftMove(e);
                    break;
                    case "leftUp":
                    leftMove(e);
                    upMove(e);
                    break;
}

移动框选区域的边界限定是保证x,y各个偏移量大于0,还要保证不超过最大宽、高度,最大高度就是

imgBox_div.offsetHeight-clipBox_div.offsetWidth,看一下实现:


    function clipBoxMove(e) {
        e.stopPropagation();

        var mouseX = e.pageX;//鼠标横坐标
        var mouseY= e.pageY;

        var boxHeight=clipBox_div.offsetHeight;
        var boxWidth=clipBox_div.offsetWidth;
        var imgBoxHeight=imgBox_div.offsetHeight;
        var imgBoxWidth=imgBox_div.offsetWidth;

        var maxY=imgBoxHeight-boxHeight;
        var maxX=imgBoxWidth-boxWidth;

        var moveX=0;
        var moveY=0;
        if(isDraging==true)
        {

            moveX=mouseX-mouseOffsetX;
            moveY=mouseY-mouseOffsetY;

            moveX=Math.max(0,moveX);
            moveY=Math.max(0,moveY);

            moveX=Math.min(maxX,moveX);
            moveY=Math.min(maxY,moveY);

            clipBox_div.style.top=moveY+"px";
            clipBox_div.style.left=moveX+"px";
        }

    }

 

4.实现实时预览区域

这个区域相对来说就好实现多了,直接来看看实现:

//截取显示区域
    function setImgVisiable() {

        var top=clipBox_div.offsetTop;
        var left=clipBox_div.offsetLeft;
        var bottom=top+clipBox_div.offsetHeight;
        var right=left+clipBox_div.offsetWidth;
        var imgTop=document.getElementById('imgTop');
        imgTop.style.clip="rect("+top+"px,"+right+"px,"+bottom+"px,"+left+"px)";

    }

    //显示预览窗口
    function setPreView() {


        var top=clipBox_div.offsetTop;
        var left=clipBox_div.offsetLeft;
        var bottom=clipBox_div.offsetTop+clipBox_div.offsetHeight;
        var right=clipBox_div.offsetLeft+clipBox_div.offsetWidth;
        var imgView=document.getElementById('imgView');
        imgView.style.clip="rect("+top+"px,"+right+"px,"+bottom+"px,"+left+"px)";

        imgView.style.top= 100-top +"px";//我选了两个定点为基准点(680,100);
        imgView.style.left=680-left +"px";
    }

5.最后还需要注意的一些问题:

(1).要在页面加载完成后消除选中不然的话鼠标拖动会被影响:

    document.onselectstart=new Function('event.returnValue=false;');

(2).使用e.stopPropagation();来阻止事件冒泡,这样的好处就是当鼠标位点击边框时它不会继续触发移动组件的效果,否则的话移动框选区和放大缩小框选区功能偶尔会粘连。

啊啊啊啊啊········写完都凌晨两点了。。。。。

这里只给大家罗列出重要的代码,因此想要实现完整样式请参考我的源码:

点我下载HTML5裁剪特效源码

如果你喜欢我的文章请收藏我的个人网站:http://www.bubblyyi.com

 

打赏

2 Comments

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注