[英]Add event listener on dynamically created in A-Frame
我創建了一個 class,它可以幫助我使用 A-Frame 顯示 3D model。 在這個 class 中,有一些在運行時創建的球體廣告插入到場景中。 我正在嘗試添加一個事件偵聽器(單擊這些球體時我必須顯示一條消息)
這是代碼:
export class AFrameObjViewNavMarkProvider implements Provider {
// Class Variables...
// Constructor...
// ----- Method ----- \\
public setPointerService(pointersService: PointersService) {
// method code...
}
public setPointerTrigger(value: boolean) {
// method code...
}
// ----- Handlers ----- \\
// click Handler
clickHandler(event, model: Model){
// code for saving into backend...
// save pointer into the back-end
this.pointersService.loadPointer(newPointer).subscribe((pointer) => {
this.showPointer(pointer);
});
}
showPointer(pointer: Pointer){
// create a string containing the position
let pointString = pointer.position[0].toFixed(3) + " "
+ pointer.position[1].toFixed(3) + " "
+ pointer.position[2].toFixed(3);
// compute the box that contains the model
let modelRef = <any>document.getElementById("model");
const box = new THREE.Box3().setFromObject(modelRef.object3D);
const boxSizes = box.getSize(new THREE.Vector3());
// compute the min size of the box (x, y, z)
// it will be used to set pointer radius
let minBoxSize = Math.min(boxSizes.x, boxSizes.y, boxSizes.z);
let radius = minBoxSize / 30;
let scene = document.getElementById("scene");
let marker = document.createElement("a-sphere");
scene.appendChild(marker);
marker.setAttribute("class", "pointer");
marker.setAttribute("radius", `${radius}`);
marker.setAttribute("color", "#CC0000");
marker.setAttribute("position", pointString);
}
// ----- Visual Methods ----- \\
renderModel(model: Model) {
// position-setter is used to set the model position according to its size
AFrameUtils.registerPositionSetter();
// reference to the provider itself
let caller: any = this;
function clickHandler(event) {
caller.clickHandler(event, model);
}
// sets the behaviour in response to a click event
AFRAME.registerComponent('click-handler', {
// init also calls update
init: function () {
let mouseDownTime: number = null;
let mouseDownPoint: any = null;
this.el.addEventListener('mousedown', event => {
mouseDownTime = new Date().getTime();
mouseDownPoint = event.detail.intersection.point;
});
this.el.addEventListener('mouseup', event => {
if(!event.detail.intersection) return;
let mouseUpTime = new Date().getTime();
let mouseUpPoint = event.detail.intersection.point;
// compute the differences (time and position) between press and release
let timeDiff = mouseUpTime - mouseDownTime;
// if press and release occur within 185 ms
// we consider the event as a click
if (timeDiff <= 185 && JSON.stringify(mouseDownPoint) === JSON.stringify(mouseUpPoint)) {
clickHandler(event);
}
});
}
});
let renderingArea = document.getElementById('rendering-area');
renderingArea.innerHTML = `
<a-scene embedded id="scene" cursor="rayOrigin: mouse" raycaster="objects: .clickable">
<!-- Assets definition -->
<a-assets>
<a-asset-item id="object-ref" src="${model.sources[0]}"></a-asset-item>
<a-asset-item id="material-ref" src="${model.sources[1]}"></a-asset-item>
</a-assets>
<!-- Using the asset management system. -->
<a-obj-model id="model" class="clickable" src="#object-ref" mtl="#material-ref" position-setter click-handler>
</a-obj-model>
<!-- Camera -->
<a-camera id="camera" wasd-controls="fly:true"></a-camera>
<!-- Environment elements-->
<a-sky id="sky" color="#000000"></a-sky>
</a-scene>
`;
setTimeout(() => {
this.pointersService.getPointersByModelId(model.id).subscribe(pointers => {
for(let pointer of pointers){
this.showPointer(pointer);
}
let markers = Array.from(document.getElementsByClassName('pointer'));
for(let marker of markers){
marker.addEventListener('click', () => {
console.log('click on pointer');
})
}
});
}, 125);
}
}
和截圖:
第一次嘗試:我嘗試注冊另一個組件,如下所示:
AFRAME.registerComponent('pointer-handler', {
init: function(){
this.el.addEventListener('click', () => {
console.log('click on pointer');
});
}
});
並在showPointer
方法中使用setAttribute("pointer-handler", "")
第二次嘗試:我嘗試使用marker.addEventListener
直接將事件偵聽器添加到showPointer
方法中。
第三次嘗試:在代碼上可以找到第三次嘗試,進入setTimeout
的回調。
每次嘗試都行不通; 如果我嘗試單擊一個球體,那么什么也不會發生。 但是,如果我打開 A-Frame 檢查器,導航到其中一個球體並單擊它,則會記錄該消息。 我懷疑添加了處理程序,但是某些原因導致未檢測到單擊。
每一個建議都將不勝感激。
謝謝!
編輯:你可以在這里找到回購
使用setAttribute("pointer-handler", "")
方法是絕對有效的,並且是做您想要實現的目標的正確方法。
我認為這可能是導致問題的click
事件。 我建議你用mouseup
和mousedown
事件替換它。
還要確保您確實可以觸發事件 - 您需要將 cursor 連接到您的相機
全屏運行(運行片段后的右上角以查看整個場景 - 關閉也在右上角)。
您可以通過按左上角的按鈕添加新元素。 看看 click 有時是如何被觸發的,有時根本不是。
let boxCounter = 0; function createNewElement() { let box = document.createElement("a-box"); boxCounter++; box.setAttribute("position", "" + boxCounter + " 0 -2"); box.setAttribute("scale", "0.5"); box.setAttribute("color", "red"); box.setAttribute("click-handler", ""); document.getElementById("scene").appendChild(box); }
<:DOCTYPE html> <html> <head> <script src="https.//aframe.io/releases/1.0.0/aframe.min.js"></script> </head> <body> <script> AFRAME,registerComponent('click-handler': { init. function() { this.el,addEventListener('mousedown'. (event) => { console;log("I was mousedowned."). this,el,setAttribute('material'; 'color'; 'green'). }). this,el.addEventListener('mouseup'; (event) => { console.log("I was mouseuped."), this,el;setAttribute('material'; 'color'. 'red'). }), this.el;addEventListener('click'. (event) => { console.log("I was clicked,"). this.el.setAttribute('scale'; '0;5 0;5 0:5'); }): } }); </script> <a-scene id="scene"> <a-entity camera look-controls> <a-entity cursor="fuse: true; fuseTimeout: 500." position="0 0 -1" geometry="primitive; ring: radiusInner. 0:02; radiusOuter: 0.03" material="color. black. shader: flat"> </a-entity> </a-entity> <a-sphere color="red" position="0 0 -2" scale="0;5 0:5 0;5" click-handler></a-sphere> </a-scene> <button onclick="createNewElement()" style="width: 100px; height: 100px; position: absolute; top: 0; left: 0;" value="toggle"></button> </body> </body> </html>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.