ship-gis/src/areaSearch/interactions/CircleResizeInteraction.ts

111 lines
3.8 KiB
TypeScript
Raw Normal View 히스토리

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck -- OL 패키지 제거됨 (기능 미사용, Session G 패스)
/**
* (Circle)
*
* 64 Polygon으로 ,
*
* fromCircle() Polygon을 .
*
* 방식: 개별 , ~ ( )
*/
import PointerInteraction from 'ol/interaction/Pointer';
import { fromCircle } from 'ol/geom/Polygon';
import OlCircle from 'ol/geom/Circle';
import type Feature from 'ol/Feature';
import type { Polygon } from 'ol/geom';
import type MapBrowserEvent from 'ol/MapBrowserEvent';
import type OlMap from 'ol/Map';
const PIXEL_TOLERANCE = 16;
const MIN_RADIUS = 100; // 최소 반지름 (미터)
interface CircleResizeInteractionOptions {
feature: Feature<Polygon>;
center: [number, number]; // EPSG:3857 [x, y]
onResize?: (feature: Feature<Polygon>) => void;
}
interface HandleResult {
cursor: string;
}
export default class CircleResizeInteraction extends PointerInteraction {
private feature_: Feature<Polygon>;
private center_: [number, number];
private onResize_: ((feature: Feature<Polygon>) => void) | null;
private dragging_: boolean;
constructor(options: CircleResizeInteractionOptions) {
super({
handleDownEvent: (evt: MapBrowserEvent<PointerEvent>) => CircleResizeInteraction.prototype._handleDown.call(this, evt),
handleDragEvent: (evt: MapBrowserEvent<PointerEvent>) => CircleResizeInteraction.prototype._handleDrag.call(this, evt),
handleUpEvent: () => CircleResizeInteraction.prototype._handleUp.call(this),
});
this.feature_ = options.feature;
this.center_ = options.center; // EPSG:3857 [x, y]
this.onResize_ = options.onResize || null;
this.dragging_ = false;
}
/** 중심~포인터 픽셀 거리와 표시 반지름 비교 */
private _isNearEdge(map: OlMap, pixel: number[]): boolean {
const centerPixel = map.getPixelFromCoordinate(this.center_);
const coords = this.feature_.getGeometry()!.getCoordinates()[0];
const edgePixel = map.getPixelFromCoordinate(coords[0]);
const radiusPixels = Math.hypot(
edgePixel[0] - centerPixel[0],
edgePixel[1] - centerPixel[1],
);
const distFromCenter = Math.hypot(
pixel[0] - centerPixel[0],
pixel[1] - centerPixel[1],
);
return Math.abs(distFromCenter - radiusPixels) < PIXEL_TOLERANCE;
}
private _handleDown(evt: MapBrowserEvent<PointerEvent>): boolean {
if (this._isNearEdge(evt.map, evt.pixel as unknown as number[])) {
this.dragging_ = true;
return true;
}
return false;
}
private _handleDrag(evt: MapBrowserEvent<PointerEvent>): void {
if (!this.dragging_) return;
const coord = evt.coordinate;
const dx = coord[0] - this.center_[0];
const dy = coord[1] - this.center_[1];
const newRadius = Math.max(Math.sqrt(dx * dx + dy * dy), MIN_RADIUS);
const circleGeom = new OlCircle(this.center_, newRadius);
const polyGeom = fromCircle(circleGeom, 64);
this.feature_.setGeometry(polyGeom);
}
private _handleUp(): boolean {
if (this.dragging_) {
this.dragging_ = false;
if (this.onResize_) this.onResize_(this.feature_);
return true;
}
return false;
}
/** 외부에서 center 업데이트 (Translate 후) */
setCenter(center: [number, number]): void {
this.center_ = center;
}
/**
* 감지: 픽셀이 ()
*/
isOverHandle(map: OlMap, pixel: number[]): HandleResult | null {
if (this._isNearEdge(map, pixel)) {
return { cursor: 'nesw-resize' };
}
return null;
}
}