mirror of
https://github.com/troisjs/trois.git
synced 2024-11-24 04:12:02 +08:00
Mesh events : mouseover, click (close #1)
This commit is contained in:
parent
adf64ecb6f
commit
9fbe5696be
@ -1,17 +1,24 @@
|
|||||||
<template>
|
<template>
|
||||||
<Renderer ref="renderer">
|
<Renderer ref="renderer" mouse-over click>
|
||||||
<Camera :position="{ z: 10 }" />
|
<Camera :position="{ z: 10 }" />
|
||||||
<Scene>
|
<Scene>
|
||||||
<PointLight :position="{ y: 50, z: 50 }" />
|
<PointLight :position="{ y: 50, z: 50 }" />
|
||||||
<Box ref="box" :size="1" :rotation="{ y: Math.PI / 4, z: Math.PI / 4 }">
|
<Group>
|
||||||
<LambertMaterial />
|
<Box ref="box" @hover="boxHover" @click="boxClick" :size="1" :rotation="{ y: Math.PI / 4, z: Math.PI / 4 }">
|
||||||
|
<LambertMaterial :color="boxColor" />
|
||||||
</Box>
|
</Box>
|
||||||
|
</Group>
|
||||||
</Scene>
|
</Scene>
|
||||||
</Renderer>
|
</Renderer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
boxColor: '#ffffff',
|
||||||
|
};
|
||||||
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
const renderer = this.$refs.renderer;
|
const renderer = this.$refs.renderer;
|
||||||
const box = this.$refs.box.mesh;
|
const box = this.$refs.box.mesh;
|
||||||
@ -19,5 +26,14 @@ export default {
|
|||||||
box.rotation.x += 0.01;
|
box.rotation.x += 0.01;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
methods: {
|
||||||
|
boxHover({ over }) {
|
||||||
|
if (over) this.boxColor = '#ff0000';
|
||||||
|
else this.boxColor = '#ffffff';
|
||||||
|
},
|
||||||
|
boxClick() {
|
||||||
|
console.log(arguments, 'click');
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -8,6 +8,8 @@ export default {
|
|||||||
autoClear: { type: Boolean, default: true },
|
autoClear: { type: Boolean, default: true },
|
||||||
mouseMove: { type: [Boolean, String], default: false },
|
mouseMove: { type: [Boolean, String], default: false },
|
||||||
mouseRaycast: { type: Boolean, default: false },
|
mouseRaycast: { type: Boolean, default: false },
|
||||||
|
mouseOver: { type: Boolean, default: false },
|
||||||
|
click: { type: Boolean, default: false },
|
||||||
orbitCtrl: { type: [Boolean, Object], default: false },
|
orbitCtrl: { type: [Boolean, Object], default: false },
|
||||||
resize: { type: [Boolean, String], default: true },
|
resize: { type: [Boolean, String], default: true },
|
||||||
shadow: Boolean,
|
shadow: Boolean,
|
||||||
@ -37,6 +39,8 @@ export default {
|
|||||||
orbit_ctrl: this.orbitCtrl,
|
orbit_ctrl: this.orbitCtrl,
|
||||||
mouse_move: this.mouseMove,
|
mouse_move: this.mouseMove,
|
||||||
mouse_raycast: this.mouseRaycast,
|
mouse_raycast: this.mouseRaycast,
|
||||||
|
mouse_over: this.mouseOver,
|
||||||
|
click: this.click,
|
||||||
resize: this.resize,
|
resize: this.resize,
|
||||||
width: this.width,
|
width: this.width,
|
||||||
height: this.height,
|
height: this.height,
|
||||||
|
@ -21,6 +21,8 @@ export default function useThree() {
|
|||||||
orbit_ctrl: false,
|
orbit_ctrl: false,
|
||||||
mouse_move: false,
|
mouse_move: false,
|
||||||
mouse_raycast: false,
|
mouse_raycast: false,
|
||||||
|
mouse_over: false,
|
||||||
|
click: false,
|
||||||
resize: true,
|
resize: true,
|
||||||
width: 0,
|
width: 0,
|
||||||
height: 0,
|
height: 0,
|
||||||
@ -44,6 +46,9 @@ export default function useThree() {
|
|||||||
const mousePlane = new Plane(new Vector3(0, 0, 1), 0);
|
const mousePlane = new Plane(new Vector3(0, 0, 1), 0);
|
||||||
const raycaster = new Raycaster();
|
const raycaster = new Raycaster();
|
||||||
|
|
||||||
|
// raycast objects
|
||||||
|
const intersectObjects = [];
|
||||||
|
|
||||||
// returned object
|
// returned object
|
||||||
const obj = {
|
const obj = {
|
||||||
conf,
|
conf,
|
||||||
@ -62,6 +67,7 @@ export default function useThree() {
|
|||||||
onAfterInit,
|
onAfterInit,
|
||||||
onAfterResize, offAfterResize,
|
onAfterResize, offAfterResize,
|
||||||
onBeforeRender, offBeforeRender,
|
onBeforeRender, offBeforeRender,
|
||||||
|
addIntersectObject, removeIntersectObject,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -103,6 +109,7 @@ export default function useThree() {
|
|||||||
window.addEventListener('resize', onResize);
|
window.addEventListener('resize', onResize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
conf.mouse_move = conf.mouse_move || conf.mouse_over;
|
||||||
if (conf.mouse_move) {
|
if (conf.mouse_move) {
|
||||||
if (conf.mouse_move === 'body') {
|
if (conf.mouse_move === 'body') {
|
||||||
obj.mouse_move_element = document.body;
|
obj.mouse_move_element = document.body;
|
||||||
@ -113,6 +120,10 @@ export default function useThree() {
|
|||||||
obj.mouse_move_element.addEventListener('mouseleave', onMouseleave);
|
obj.mouse_move_element.addEventListener('mouseleave', onMouseleave);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (conf.click) {
|
||||||
|
obj.renderer.domElement.addEventListener('click', onClick);
|
||||||
|
}
|
||||||
|
|
||||||
afterInitCallbacks.forEach(c => c());
|
afterInitCallbacks.forEach(c => c());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -171,6 +182,25 @@ export default function useThree() {
|
|||||||
obj.composer.render();
|
obj.composer.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* add intersect object
|
||||||
|
*/
|
||||||
|
function addIntersectObject(o) {
|
||||||
|
if (intersectObjects.indexOf(o) === -1) {
|
||||||
|
intersectObjects.push(o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* remove intersect object
|
||||||
|
*/
|
||||||
|
function removeIntersectObject(o) {
|
||||||
|
const i = intersectObjects.indexOf(o);
|
||||||
|
if (i !== -1) {
|
||||||
|
intersectObjects.splice(i, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* remove listeners
|
* remove listeners
|
||||||
*/
|
*/
|
||||||
@ -181,38 +211,77 @@ export default function useThree() {
|
|||||||
obj.mouse_move_element.removeEventListener('mousemove', onMousemove);
|
obj.mouse_move_element.removeEventListener('mousemove', onMousemove);
|
||||||
obj.mouse_move_element.removeEventListener('mouseleave', onMouseleave);
|
obj.mouse_move_element.removeEventListener('mouseleave', onMouseleave);
|
||||||
}
|
}
|
||||||
|
obj.renderer.domElement.removeEventListener('click', onClick);
|
||||||
if (obj.orbitCtrl) obj.orbitCtrl.dispose();
|
if (obj.orbitCtrl) obj.orbitCtrl.dispose();
|
||||||
this.renderer.dispose();
|
this.renderer.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* click listener
|
||||||
|
*/
|
||||||
|
function onClick(e) {
|
||||||
|
mouse.x = (e.clientX / size.width) * 2 - 1;
|
||||||
|
mouse.y = -(e.clientY / size.height) * 2 + 1;
|
||||||
|
raycaster.setFromCamera(mouse, obj.camera);
|
||||||
|
const objects = raycaster.intersectObjects(intersectObjects);
|
||||||
|
for (let i = 0; i < objects.length; i++) {
|
||||||
|
const o = objects[i].object;
|
||||||
|
if (o.onClick) o.onClick(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mousemove listener
|
* mousemove listener
|
||||||
*/
|
*/
|
||||||
function onMousemove(e) {
|
function onMousemove(e) {
|
||||||
mouse.x = (e.clientX / size.width) * 2 - 1;
|
mouse.x = (e.clientX / size.width) * 2 - 1;
|
||||||
mouse.y = -(e.clientY / size.height) * 2 + 1;
|
mouse.y = -(e.clientY / size.height) * 2 + 1;
|
||||||
updateMouseV3();
|
onMousechange(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mouseleave listener
|
* mouseleave listener
|
||||||
*/
|
*/
|
||||||
function onMouseleave(e) {
|
function onMouseleave(e) {
|
||||||
mouse.x = 0;
|
// mouse.x = 0;
|
||||||
mouse.y = 0;
|
// mouse.y = 0;
|
||||||
updateMouseV3();
|
onMousechange(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get 3d mouse position
|
* mouse change
|
||||||
*/
|
*/
|
||||||
function updateMouseV3() {
|
function onMousechange(e) {
|
||||||
|
if (conf.mouse_over || conf.mouse_raycast) {
|
||||||
|
raycaster.setFromCamera(mouse, obj.camera);
|
||||||
|
|
||||||
if (conf.mouse_raycast) {
|
if (conf.mouse_raycast) {
|
||||||
|
// get mouse 3d position
|
||||||
obj.camera.getWorldDirection(mousePlane.normal);
|
obj.camera.getWorldDirection(mousePlane.normal);
|
||||||
mousePlane.normal.normalize();
|
mousePlane.normal.normalize();
|
||||||
raycaster.setFromCamera(mouse, obj.camera);
|
|
||||||
raycaster.ray.intersectPlane(mousePlane, mouseV3);
|
raycaster.ray.intersectPlane(mousePlane, mouseV3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (conf.mouse_over) {
|
||||||
|
const onObjects = raycaster.intersectObjects(intersectObjects);
|
||||||
|
const offObjects = [...intersectObjects];
|
||||||
|
for (let i = 0; i < onObjects.length; i++) {
|
||||||
|
const o = onObjects[i].object;
|
||||||
|
if (!o.hover && o.onHover) {
|
||||||
|
o.hover = true;
|
||||||
|
o.onHover(true);
|
||||||
|
}
|
||||||
|
offObjects.splice(offObjects.indexOf(o), 1);
|
||||||
|
}
|
||||||
|
for (let i = 0; i < offObjects.length; i++) {
|
||||||
|
const o = offObjects[i];
|
||||||
|
if (o.hover && o.onHover) {
|
||||||
|
o.hover = false;
|
||||||
|
o.onHover(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -12,6 +12,8 @@ export default {
|
|||||||
scale: Object,
|
scale: Object,
|
||||||
castShadow: Boolean,
|
castShadow: Boolean,
|
||||||
receiveShadow: Boolean,
|
receiveShadow: Boolean,
|
||||||
|
onHover: Function,
|
||||||
|
onClick: Function,
|
||||||
},
|
},
|
||||||
// can't use setup because it will not be used in sub components
|
// can't use setup because it will not be used in sub components
|
||||||
// setup() {},
|
// setup() {},
|
||||||
@ -29,7 +31,10 @@ export default {
|
|||||||
},
|
},
|
||||||
unmounted() {
|
unmounted() {
|
||||||
// console.log('Mesh unmounted');
|
// console.log('Mesh unmounted');
|
||||||
if (this.mesh) this.parent.remove(this.mesh);
|
if (this.mesh) {
|
||||||
|
this.three.removeIntersectObject(this.mesh);
|
||||||
|
this.parent.remove(this.mesh);
|
||||||
|
}
|
||||||
if (this.geometry) this.geometry.dispose();
|
if (this.geometry) this.geometry.dispose();
|
||||||
if (this.material && !this.materialId) this.material.dispose();
|
if (this.material && !this.materialId) this.material.dispose();
|
||||||
},
|
},
|
||||||
@ -39,6 +44,17 @@ export default {
|
|||||||
this.material = this.three.materials[this.materialId];
|
this.material = this.three.materials[this.materialId];
|
||||||
}
|
}
|
||||||
this.mesh = new Mesh(this.geometry, this.material);
|
this.mesh = new Mesh(this.geometry, this.material);
|
||||||
|
|
||||||
|
if (this.onHover) {
|
||||||
|
this.mesh.onHover = (over) => { this.onHover({ component: this, over }); };
|
||||||
|
this.three.addIntersectObject(this.mesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.onClick) {
|
||||||
|
this.mesh.onClick = (e) => { this.onClick({ component: this, event: e }); };
|
||||||
|
this.three.addIntersectObject(this.mesh);
|
||||||
|
}
|
||||||
|
|
||||||
this.bindProps();
|
this.bindProps();
|
||||||
this.parent.add(this.mesh);
|
this.parent.add(this.mesh);
|
||||||
this.$emit('ready');
|
this.$emit('ready');
|
||||||
|
Loading…
Reference in New Issue
Block a user