search

Home  >  Q&A  >  body text

javascript - Canvas 内部元素如何实现 mouseover/mousemove 事件?

我在使用 Collie 引擎 来开发一个简单的游戏,它提供了 mousedown、mouseup、click 这三个鼠标事件,但是我想实现的功能是:当我的鼠标移到元素上的时候,显示该元素的名字。但这个引擎并没有提供 mouseover 或 mousemove 事件。

Canvas 是不是只能通过获取指针在画面上的坐标,然后判断是否在元素的范围,来模拟这个事件?

如果是的话,有什么好的算法,用来判断指针是否在 x、y、width、height (或者是圆型 x、y、radius) 范围中?

如果不是的话,应该怎么做呢?

PHP中文网PHP中文网2902 days ago542

reply all(2)I'll reply

  • 黄舟

    黄舟2017-04-10 14:54:57

    自己看源代碼不就好了

    和我想得一樣,就是循環判斷,比大小確定範圍,直到找到爲止。

    想要實現 mouseover 啥的,自己照着 _fireEvent 調用 _getTargetOnHitEvent 即可

    /**
     * 레이어에서 이벤트가 일어났을 때 표시 객체에 이벤트를 발생 시킨다
     * 
     * @param {Object} e 이벤트 원본
     * @param {String} sType 이벤트 타입, mouse 이벤트로 변형되서 들어온다
     * @param {Number} nX 이벤트가 일어난 상대좌표
     * @param {Number} nY 이벤트가 일어난 상대좌표
     * @return {Boolean} 표시 객체에 이벤트가 발생했는지 여부 
     * @private
     */
    _fireEvent : function (e, sType, nX, nY) {
        var oDisplayObject = null;
        var bIsNotStoppedBubbling = true;
    
        // 캔버스에서 이전 레이어에 객체에 이벤트가 일어났으면 다음 레이어의 객체에 전달되지 않는다
        if (sType !== "mousemove" && !collie.Renderer.isStopEvent(sType)) {
            var aDisplayObjects = this._oLayer.getChildren();
            oDisplayObject = this._getTargetOnHitEvent(aDisplayObjects, nX, nY);
    
            // mousedown일 경우 객체를 저장한다
            if (oDisplayObject) {
                bIsNotStoppedBubbling = this._bubbleEvent(oDisplayObject, sType, e, nX, nY);
    
                if (sType === "mousedown") {
                    this._setMousedownObject(oDisplayObject);
                }
                if (sType === "mouseup") {
                    this._unsetMousedownObject(oDisplayObject);
                }
            }
        }
    
        // mouseup 처리가 안된 경우 임의 발생
        if (sType === "mouseup" && this._getMousedownObject() !== null) {
            oDisplayObject = this._getMousedownObject();
            this._bubbleEvent(oDisplayObject, sType, e, nX, nY);
            this._unsetMousedownObject(oDisplayObject);
        }
    
        /**
         * click 이벤트, 모바일 환경일 때는 touchstart, touchend를 비교해서 좌표가 일정 이내로 움직였을 경우 click 이벤트를 발생한다d
         * @name collie.Layer#click
         * @event
         * @param {Object} htEvent
         * @param {collie.DisplayObject} htEvent.displayObject 대상 객체
         * @param {HTMLEvent} htEvent.event 이벤트 객체
         * @param {Number} htEvent.x 상대 x좌표
         * @param {Number} htEvent.y 상대 y좌표
         */
        /**
         * mousedown 이벤트, 모바일 환경일 때는 touchstart 이벤트도 해당 된다.
         * @name collie.Layer#mousedown
         * @event
         * @param {Object} htEvent
         * @param {collie.DisplayObject} htEvent.displayObject 대상 객체
         * @param {HTMLEvent} htEvent.event 이벤트 객체
         * @param {Number} htEvent.x 상대 x좌표
         * @param {Number} htEvent.y 상대 y좌표
         */
        /**
         * mouseup 이벤트, 모바일 환경일 때는 touchend 이벤트도 해당 된다.
         * @name collie.Layer#mouseup
         * @event
         * @param {Object} htEvent
         * @param {collie.DisplayObject} htEvent.displayObject 대상 객체
         * @param {HTMLEvent} htEvent.event 이벤트 객체
         * @param {Number} htEvent.x 상대 x좌표
         * @param {Number} htEvent.y 상대 y좌표
         */
        /**
         * mousemove 이벤트, 모바일 환경일 때는 touchmove 이벤트도 해당 된다.
         * @name collie.Layer#mouseup
         * @event
         * @param {Object} htEvent
         * @param {collie.DisplayObject} htEvent.displayObject 대상 객체
         * @param {HTMLEvent} htEvent.event 이벤트 객체
         * @param {Number} htEvent.x 상대 x좌표
         * @param {Number} htEvent.y 상대 y좌표
         */
        if (bIsNotStoppedBubbling) { // stop되면 Layer이벤트도 일어나지 않는다
            this._oLayer.fireEvent(sType, {
                event : e,
                displayObject : oDisplayObject,
                x : nX,
                y : nY
            });
        }
    
        return !!oDisplayObject;
    },
    
    /**
     * 이벤트 대상을 고른다
     * - 가장 위에 있는 대상이 선정되어야 한다
     * @private
     * @param {Array|collie.DisplayObject} vDisplayObject
     * @param {Number} nX 이벤트 상대 x 좌표
     * @param {Number} nY 이벤트 상대 y 좌표
     * @return {collie.DisplayObject|Boolean}
     */
    _getTargetOnHitEvent : function (vDisplayObject, nX, nY) {
        var oTargetObject = null;
    
        if (vDisplayObject instanceof Array) {
            for (var i = vDisplayObject.length - 1; i >= 0; i--) {
                // 자식부터
                if (vDisplayObject[i].hasChild()) {
                    oTargetObject = this._getTargetOnHitEvent(vDisplayObject[i].getChildren(), nX, nY);
    
                    // 찾았으면 멈춤
                    if (oTargetObject) {
                        return oTargetObject;
                    }
                }
    
                // 본인도
                oTargetObject = this._getTargetOnHitEvent(vDisplayObject[i], nX, nY);
    
                // 찾았으면 멈춤
                if (oTargetObject) {
                    return oTargetObject;
                }
            }
        } else {
            return this._isPointInDisplayObjectBoundary(vDisplayObject, nX, nY) ? vDisplayObject : false;
        }
    },
    
    
    /**
     * DisplayObject 범위 안에 PointX, PointY가 들어가는지 확인
     * 
     * @private
     * @param {collie.DisplayObject} oDisplayObject
     * @param {Number} nPointX 확인할 포인트 X 좌표
     * @param {Number} nPointY 확인할 포인트 Y 좌표
     * @return {Boolean} 들어간다면 true
     */
    _isPointInDisplayObjectBoundary : function (oDisplayObject, nPointX, nPointY) {
        // 안보이는 상태거나 이벤트를 받지 않는다면 지나감
        if (
            !oDisplayObject._htOption.useEvent ||
            !oDisplayObject._htOption.visible ||
            !oDisplayObject._htOption.width ||
            !oDisplayObject._htOption.height ||
            (oDisplayObject._htOption.useEvent === "auto" && !oDisplayObject.hasAttachedHandler())
            ) {
            return false;
        }
    
        var htHitArea = oDisplayObject.getHitAreaBoundary();
    
        // 영역 안에 들어왔을 경우
        if (
            htHitArea.left <= nPointX && nPointX <= htHitArea.right &&
            htHitArea.top <= nPointY && nPointY <= htHitArea.bottom
        ) {
            // hitArea 설정이 없으면 사각 영역으로 체크
            if (!oDisplayObject._htOption.hitArea) {
                return true;
            } else {
                var htPos = oDisplayObject.getRelatedPosition();
    
                // 대상 Point를 상대 좌표로 변경
                nPointX -= htPos.x;
                nPointY -= htPos.y;
    
                // transform 적용
                var aHitArea = oDisplayObject._htOption.hitArea;
                aHitArea = collie.Transform.points(oDisplayObject, aHitArea);
                return this._isPointInPolygon(aHitArea, nPointX, nPointY);
            }
        }
    
        return false;
    },
    

    reply
    0
  • 伊谢尔伦

    伊谢尔伦2017-04-10 14:54:57

    使用 addEventListener() 监听事件,并执行相应函数

    canvas.addEventListener('mousemove',mouseMove,false);   //监听鼠标移动
    canvas.addEventListener('mousedown',mouseDown,false);   //监听鼠标按下
    canvas.addEventListener('mouseup',mouseUp,false);       //监听鼠标松开
    canvas.addEventListener('mouseout',mouseUp,false);      //监听鼠标离开
    canvas.addEventListener('dblclick',doubleClick,false);  //监听鼠标双击

    可参考:http://canvas.migong.org/191.html

    reply
    0
  • Cancelreply