map-interaction/dist/core/TouchRing.js

95 lines
3.5 KiB
JavaScript

import { Vector2 } from './Vector2';
import { Direction } from './types/TouchData';
export class TouchRing {
constructor(parent, size) {
this.parent = parent;
this.size = size;
this.isTouching = false;
this.element = document.createElement('div');
this.radius = size / 2;
this.center = new Vector2(this.radius, this.radius);
this.initElement();
this.initEvents();
}
initElement() {
this.element.style.width = `${this.size}px`;
this.element.style.height = `${this.size}px`;
this.element.style.borderRadius = '50%';
this.element.style.backgroundColor = '#5ab5da';
this.element.style.opacity = '0.7';
this.element.style.position = 'absolute';
this.element.style.left = '5%';
this.element.style.bottom = '5%';
this.element.style.touchAction = 'none';
this.parent.appendChild(this.element);
}
initEvents() {
this.element.addEventListener('touchstart', this.handleTouchStart.bind(this));
this.element.addEventListener('touchmove', this.handleTouchMove.bind(this));
this.element.addEventListener('touchend', this.handleTouchEnd.bind(this));
}
handleTouchStart(event) {
event.preventDefault();
this.isTouching = true;
}
handleTouchMove(event) {
if (!this.isTouching)
return;
event.preventDefault();
const touch = event.touches[0];
const rect = this.element.getBoundingClientRect();
const touchPos = new Vector2(touch.clientX - rect.left, touch.clientY - rect.top);
const touchData = this.calculateTouchData(touchPos);
this.dispatchTouchEvent(touchData);
}
handleTouchEnd() {
this.isTouching = false;
this.dispatchTouchEvent({
direction: Direction.None,
speedFactor: 1,
normalizedPosition: new Vector2()
});
}
calculateTouchData(touchPos) {
const offset = touchPos.subtract(this.center);
const distance = offset.length();
const clampedDistance = Math.min(distance, this.radius);
// 计算速度因子
const speedFactor = 0.8 + (clampedDistance / this.radius) * 0.4;
// 计算方向
const angle = Math.atan2(offset.y, offset.x);
const direction = this.getDirectionFromAngle(angle);
// 归一化位置
const normalizedPosition = offset.scale(1 / this.radius);
return {
direction,
speedFactor,
normalizedPosition
};
}
getDirectionFromAngle(angle) {
const pi = Math.PI;
if (angle >= -pi / 8 && angle < pi / 8)
return Direction.Right;
if (angle >= pi / 8 && angle < 3 * pi / 8)
return Direction.UpRight;
if (angle >= 3 * pi / 8 && angle < 5 * pi / 8)
return Direction.Up;
if (angle >= 5 * pi / 8 && angle < 7 * pi / 8)
return Direction.UpLeft;
if (angle >= 7 * pi / 8 || angle < -7 * pi / 8)
return Direction.Left;
if (angle >= -7 * pi / 8 && angle < -5 * pi / 8)
return Direction.DownLeft;
if (angle >= -5 * pi / 8 && angle < -3 * pi / 8)
return Direction.Down;
if (angle >= -3 * pi / 8 && angle < -pi / 8)
return Direction.DownRight;
return Direction.None;
}
dispatchTouchEvent(data) {
const event = new CustomEvent('touchChange', { detail: data });
this.element.dispatchEvent(event);
}
}