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

View File

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

View File

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