【前端】Canvas 内部元素如何实现 mouseover/mousemove 事件?
我在使用 Collie 引擎 来开发一个简单的游戏,它提供了 mousedown、mouseup、click 这三个鼠标事件,但是我想实现的功能是:当我的鼠标移到元素上的时候,显示该元素的名字。但这个引擎并没有提供 mouseover 或 mousemove 事件。
Canvas 是不是只能通过获取指针在画面上的坐标,然后判断是否在元素的范围,来模拟这个事件?
如果是的话,有什么好的算法,用来判断指针是否在 x、y、width、height (或者是圆型 x、y、radius) 范围中?
如果不是的话,应该怎么做呢?
回答
自己看源代碼不就好了
和我想得一樣,就是循環判斷,比大小確定範圍,直到找到爲止。
想要實現 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;
},
使用 addEventListener() 监听事件,并执行QQ号码买卖地图相应函数
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); //监听鼠标双击
更多相关文章
- 【前端】添加draggable 属性,无论怎么设置都无法触发dragstart后
- js事件,线程,定时器
- Vue一个通用的组件传递点击事件的两种种简单方法
- 轮播图自动翻页功能实现
- 事件的添加方式
- 表单元素及表单事件
- JS执行机制、事件模型、表单事件、事件冒泡、fetch的常用场景
- 任务队列、事件、冒泡、fetch使用
- JavaScript onblur与onfocus事件详解