web 不规则图片拖动

不规则图片点击识别

众所周知,图片都是矩形的,但是有些图片是一个美女,一只猫or狗,这时候,我们希望可以把美女,带到我们的黄金屋去,噼里啪啦,搞定!

enter image description here

找不到美女,找到了一头狼

嗯,可以移动了,可是,图片是矩形的,点击矩形的透明区域,图片也跟着移动了,在用户眼中,他们才不管你的是矩形圆形,他们要的是效果:

enter image description here

所以,需要判断图片的不规则区域,触摸的是该区域,才移动,我们再次拖动图片的透明区域,灰太狼是不动的,这里我们用到了一个getImageData去获取canvas点击处的像素,以判断该处是否透明,官方文档如下:



所以,我们在触摸事件中加如入代码:

var imgData = this.myctx.getImageData(x,y, 1, 1);
var alpha = imgData.data[3];

this.myctx.needMove = alpha > 0;

根据needMove判断是否移动,部分代码如下index-canvas.html:

function touchLister(event) {

    var event = event || window.event;

    switch(event.type) {
        case "touchstart":
            var touchEvent = event.changedTouches[0];
            var offsetLeft = event.target.offsetLeft;
            var offsetTop  = event.target.offsetTop;

            this.myctx.startX  = touchEvent.pageX - offsetLeft;
            this.myctx.startY  = touchEvent.pageY - offsetTop;

            var x  = parseInt(touchEvent.pageX - offsetLeft),
                y  = parseInt(touchEvent.pageY - offsetTop);

            var imgData = this.myctx.getImageData(x,y, 1, 1);
            var alpha = imgData.data[3];

            this.myctx.needMove = alpha > 0;
            break;

        case "touchmove":
            if (this.myctx.needMove){
                this.style.left = (event.changedTouches[0].pageX - this.myctx.startX) + 'px';
                this.style.top = (event.changedTouches[0].pageY - this.myctx.startY) + 'px';
            }

            event.preventDefault();
            break;

        case "touchend":

            break;
    }
}

图片的重叠问题

enter image description here

当界面上的不规则图形 > 1 的时候,以上图为例,我们想要拖动在狼后面的羊,由于有一部分被狼图片的透明部分所挡住,当我们想要拖动羊而恰好拖动的触摸点在这部分的范围内时,是无法拖动后面的羊,当然,你可以这么做:

  • 整体使用一个canvas,记录每个图片的信息,然后不断的重绘,遇到羊和狼重叠的部分,需要先判断是否点击处的坐标是否是在狼身上,还是在狼的透明区域上,若在透明区域上,需要再判断是在羊身上,还是在羊透明区域上,若在羊身上,移动羊
  • 使用轮子,好吧,站在巨人的肩膀上再走一回,谁让咱懒捏

该部分代码见demo(index-canvas.html)


使用动画库collie

collie是一个 JavaScript 库,用于为移动平台创建优化的动画和游戏

使用collie加载一只狼
oLayer = new collie.Layer({
    width: clientWidth,
    height: clientHeight
}); 

//加载图片 
collie.ImageManager.add('img1', 'img/pic1.png');  

new collie.DisplayObject({
            width: 302,
            height: 316,
            x: 0,
            y: 0,
            backgroundImage: 'imgs1'
        }).addTo(oLayer);

Layer是一个容器,可以在里面放图片对象DisplayObject,以上代码效果如下:



狼太大了,需要进行缩放,将大小变为原来的一半

new collie.DisplayObject({
        width: 302,
        height: 316,
        x: 0,
        y: 0,
        backgroundImage: 'imgs1',
        originX: 'left',
        originY: 'top',//1
        scaleX: 0.5,
        scaleY: 0.5,
    }).addTo(oLayer);  

1.任何一个元素都有一个中心点,默认情况之下,其中心点是居于元素X轴和Y轴的50%处,不改变该点情况下,进行的旋转、位移、缩放,扭曲等操作都是以元素自己中心位置进行变形,此处将该点改为左上角,效果见下图



让狼动起来
new collie.DisplayObject({
        width: 302,
        height: 316,
        x: 0,
        y: 0,
        backgroundImage: 'imgs1',
        originX: 'left',
        originY: 'top',
        scaleX: 0.5,
        scaleY: 0.5,
        useEvent: true//1
    }).addTo(oLayer);    

 oLayer.attach({
    mousedown: function(oEvent) {
        if(oEvent.displayObject) {
            oSelectedDisplayObject = oEvent.displayObject;
            htStartPosition = {
                x: oEvent.x,
                y: oEvent.y
            };
            htSelectedDisplayObjectPosition = {
                x: oSelectedDisplayObject.get("x"),
                y: oSelectedDisplayObject.get("y")
            };//2
        }
    },
    mouseup: function(oEvent) {
        if(oSelectedDisplayObject !== null) {
            oSelectedDisplayObject = null;
            htSelectedDisplayObjectPosition = htStartPosition = {};
        }
    },
    mousemove: function(oEvent) {
        if(oSelectedDisplayObject !== null) {
            var x = htStartPosition.x - oEvent.x;
            var y = htStartPosition.y - oEvent.y;
            oSelectedDisplayObject.set({
                x: htSelectedDisplayObjectPosition.x - x,
                y: htSelectedDisplayObjectPosition.y - y
            });//3
        }
    }
});  

1.设置图片对象响应事件
2.记录鼠标按下时的坐标,当前图片的x,y
3.根据上一步记录的坐标和当前的坐标的差值,可以知道移动了多少,相应的让图片也移动这个差值,实现拖动效果



区域拖动

狼的拖动已经实现了,但是又回到了一开始的问题,不规则点击识别,collie已经给我们考虑到了,collie.DisplayObject有一个参数hitArea,官方文档:



可以设置某个区域响应事件,如下图:



红色圈起来的为可响应区域,该区域由一些点组成,collie很贴心的提供了工具供我们生成这些点,传送门,代码:

hitArea: [
    [[x1,y1],[x2,y2]]
]

运行效果如下:



区域拖动实现了,但是仔细观察会发现,大灰狼会越界,超出黄色的范围,对此,可以设置collie.DisplayObjectrangeXrangeY,文档:



rangeX: [0, clientWidth - sizes[i][0] * scale],
rangeY: [0, clientHeight - sizes[i][1] * scale],  


设置了范围之后,可以防止超出黄色区域

加多点动物


这里在按下事件中,将选中的displayObject移除,重新添加,实现了被选中的动物移动最前面:

mousedown: function(oEvent) {
        if(oEvent.displayObject) {
            oSelectedDisplayObject = oEvent.displayObject;
            htStartPosition = {
                x: oEvent.x,
                y: oEvent.y
            };
            htSelectedDisplayObjectPosition = {
                x: oSelectedDisplayObject.get("x"),
                y: oSelectedDisplayObject.get("y")
            };

            oLayer.removeChild(oEvent.displayObject);
            oLayer.addChild(oEvent.displayObject);
        }
    },  

至此,对于上面的图片重叠问题,也算是解决啦!该部分代码见demo(index-collie.html)