added mouse click

This commit is contained in:
azykov@mail.ru 2026-05-20 21:28:26 +03:00
parent bd5fa12a1e
commit 0a750606ac
No known key found for this signature in database
3 changed files with 48 additions and 13 deletions

View File

@ -1,10 +1,9 @@
import { useEffect, useRef } from "react";
import * as THREE from 'three';
import { useInteraction, type InteractionMouseMoveEventArgs } from "../helpers/hooks/useInteration";
import { useInteraction, type InteractionMouseEventArgs } from "../helpers/hooks/useInteration";
import { db } from "../backend/db";
import { HitTestFactory, type HitTest } from "../helpers/hitTest";
import { model } from "../model/model";
import { Point3dHelper } from "../helpers/point3dHelper";
import { SceneHelper } from "../helpers/sceneHelper";
export type ThreeViewEventArgs = {
@ -17,14 +16,15 @@ export type ThreeViewTickEventArgs = ThreeViewEventArgs & {
absoluteTime: number,
}
export type ThreeViewMouseMoveEventArgs = ThreeViewEventArgs & {
export type ThreeViewMouseEventArgs = ThreeViewEventArgs & {
hitTest: HitTest,
}
export type ThreeViewProps = {
sceneHelper: SceneHelper,
onTick?: (event: ThreeViewTickEventArgs) => void,
onMouseMove?: (event: ThreeViewMouseMoveEventArgs) => void,
onClick?: (event: ThreeViewMouseEventArgs) => void,
onMouseMove?: (event: ThreeViewMouseEventArgs) => void,
onDispose: (event: ThreeViewEventArgs) => void,
}
@ -67,7 +67,8 @@ export const ThreeView = function (props: ThreeViewProps) {
const canvasRef = useRef<HTMLCanvasElement | null>(null);
const cameraRef = useRef<THREE.PerspectiveCamera | null>(null);
let handleHover: (e: InteractionMouseMoveEventArgs) => void;
let handleClick: (e: InteractionMouseEventArgs) => void;
let handleHover: (e: InteractionMouseEventArgs) => void;
useEffect(() => {
@ -100,7 +101,7 @@ export const ThreeView = function (props: ThreeViewProps) {
};
window.addEventListener("resize", handleWindowResize);
handleHover = (e: InteractionMouseMoveEventArgs) => {
handleHover = (e: InteractionMouseEventArgs) => {
const hitTest = HitTestFactory.hitTest(
props.sceneHelper,
new THREE.Vector2(e.position.x, e.position.y),
@ -114,6 +115,20 @@ export const ThreeView = function (props: ThreeViewProps) {
});
};
handleClick = (e: InteractionMouseEventArgs) => {
const hitTest = HitTestFactory.hitTest(
props.sceneHelper,
new THREE.Vector2(e.position.x, e.position.y),
camera,
{ tolerancePixels: 3, cameraPixelSize: e.pixelSize }
);
props.onClick?.({
camera,
scene,
hitTest,
})
};
// --- Animation loop ---
let lastTime = performance.now();
let animId: number;
@ -153,6 +168,7 @@ export const ThreeView = function (props: ThreeViewProps) {
useInteraction(canvasRef, cameraRef, {
onMouseMove: (e) => handleHover?.(e),
onMouseClick: (e) => handleClick?.(e),
});
return (

View File

@ -1,14 +1,12 @@
import { useState } from "react";
import { useSceneHelper } from "../helpers/hooks/useSceneHelper";
import { Point3dHelper } from "../helpers/point3dHelper";
import { state } from "../state/root";
import { ThreeView, type ThreeViewEventArgs, type ThreeViewMouseMoveEventArgs } from "./ThreeVIew";
import { ThreeView, type ThreeViewEventArgs, type ThreeViewMouseEventArgs } from "./ThreeVIew";
export const Viewport = function () {
const sceneHelper = useSceneHelper();
function handleMouseMove(e: ThreeViewMouseMoveEventArgs) {
function handleMouseMove(e: ThreeViewMouseEventArgs) {
state.setHitTest(e.hitTest);
sceneHelper.clearPoints();
@ -33,10 +31,15 @@ export const Viewport = function () {
// throw new Error("Function not implemented.");
}
function handleClick(e: ThreeViewMouseEventArgs): void {
console.log(e);
}
return (<>
<ThreeView
sceneHelper={sceneHelper}
onMouseMove={handleMouseMove}
onClick={handleClick}
onDispose={handleDispose}
/>
</>);

View File

@ -1,13 +1,16 @@
import { useEffect, type RefObject } from "react";
import * as THREE from "three";
export type InteractionMouseMoveEventArgs = {
const CLICK_THRESHOLD = 2; // px
export type InteractionMouseEventArgs = {
position: { x: number, y: number },
pixelSize: { x: number, y: number },
};
export type UseInteractionOptions = {
onMouseMove?: (e: InteractionMouseMoveEventArgs) => void,
onMouseClick?: (e: InteractionMouseEventArgs) => void,
onMouseMove?: (e: InteractionMouseEventArgs) => void,
}
export function useInteraction(
@ -29,6 +32,7 @@ export function useInteraction(
// --- Orbit Controls (manual implementation, no OrbitControls import needed) ---
let isDragging = false;
let isRightDrag = false;
let startX = 0, startY = 0;
let lastX = 0, lastY = 0;
let theta = 0.8, phi = 0.9, radius = 8;
let targetX = 0, targetY = 0;
@ -44,12 +48,24 @@ export function useInteraction(
const onMouseDown = (e: MouseEvent) => {
isDragging = true;
isRightDrag = e.button === 2;
startX = e.clientX;
startY = e.clientY;
lastX = e.clientX;
lastY = e.clientY;
e.preventDefault();
};
const onMouseUp = () => { isDragging = false; };
const onMouseUp = (e: MouseEvent) => {
isDragging = false;
if ((e.clientX - startX < CLICK_THRESHOLD) && (e.clientY - startY < CLICK_THRESHOLD)) {
const rect = target.getBoundingClientRect();
const position = {
x: ((e.clientX - rect.left) / rect.width) * 2 - 1,
y: -((e.clientY - rect.top) / rect.height) * 2 + 1,
};
options.onMouseClick?.({ position, pixelSize: { x: 2 / rect.width, y: 2 / rect.height } });
}
};
const onMouseMove = (e: MouseEvent) => {
if (!isDragging) return;