web-map/src/services/area-operation.service.ts

187 lines
5.6 KiB
TypeScript
Raw Normal View History

import type { MapAreaInfo, MapPen } from '@api/map';
import { MapAreaType, MapPointType } from '@api/map';
/**
*
*
*/
export class AreaOperationService {
/**
*
*
* @param pen
* @param findPoints
* @param updateArea
*/
public handleAreaSizeChange(
pen: MapPen,
findPoints: (type: string) => MapPen[],
updateArea: (id: string, info: Partial<MapAreaInfo>) => void,
): void {
// 检查是否为区域类型
if (!pen.area?.type || !['area'].includes(pen.tags?.[0] || '')) {
return;
}
const areaType = pen.area.type;
// 只处理互斥区和非互斥区
if (![MapAreaType., MapAreaType.].includes(areaType)) {
return;
}
// 获取区域边界
const areaRect = this.getPenRect(pen);
if (!areaRect) {
return;
}
// 查找所有点位
const allPoints = findPoints('point') as MapPen[];
// 根据区域类型过滤点位,借鉴 addArea 的逻辑
const containedPoints: string[] = [];
const currentBoundPoints = pen.area.points || [];
allPoints.forEach((point) => {
if (!point.point?.type) return;
// 根据区域类型过滤点位类型
let shouldInclude = false;
switch (areaType) {
case MapAreaType.:
case MapAreaType.:
// 互斥区和非互斥区绑定所有类型的点位
shouldInclude = true;
break;
case MapAreaType.:
// 库区只绑定动作点
shouldInclude = point.point.type === MapPointType.;
break;
case MapAreaType.:
// 约束区绑定所有类型的点位
shouldInclude = true;
break;
default:
shouldInclude = false;
break;
}
if (!shouldInclude) return;
// 检查点位是否在区域内(使用点位中心坐标)
const pointCenter = this.getPointRect(point);
if (!pointCenter) return;
const isContained = this.isPointInArea(pointCenter, areaRect);
if (isContained) {
containedPoints.push(point.id!);
}
});
// 找出新包含的点位(之前未绑定的)
const newPoints = containedPoints.filter((id) => !currentBoundPoints.includes(id));
// 找出需要解绑的点位(之前绑定但现在不在区域内的)
const removedPoints = currentBoundPoints.filter((id) => !containedPoints.includes(id));
if (newPoints.length > 0 || removedPoints.length > 0) {
// 更新区域绑定的点位:保留仍在区域内的点位,添加新包含的点位
const updatedPoints = containedPoints;
updateArea(pen.id!, { points: updatedPoints });
}
}
/**
*
* @param point
* @param area
* @returns
*/
private isPointInArea(
point: { x: number; y: number },
area: { x: number; y: number; width: number; height: number },
): boolean {
return point.x >= area.x && point.x <= area.x + area.width && point.y >= area.y && point.y <= area.y + area.height;
}
/**
*
* @param pen
* @returns
*/
private getPenRect(pen: MapPen): { x: number; y: number; width: number; height: number } | null {
if (!pen.x || !pen.y || !pen.width || !pen.height) {
return null;
}
return {
x: pen.x,
y: pen.y,
width: pen.width,
height: pen.height,
};
}
/**
*
* @param pen
* @returns
*/
private getPointRect(pen: MapPen): { x: number; y: number; width: number; height: number } | null {
if (!pen.x || !pen.y || !pen.width || !pen.height) {
return null;
}
return {
x: pen.x + pen.width / 2,
y: pen.y + pen.height / 2,
width: pen.width,
height: pen.height,
};
}
/**
*
*
* @param areaId ID
* @param getPenById ID获取图形对象的函数
* @param findPoints
* @param updateArea
*/
public checkAndUpdateAreaPoints(
areaId: string,
getPenById: (id: string) => MapPen | undefined,
findPoints: (type: string) => MapPen[],
updateArea: (id: string, info: Partial<MapAreaInfo>) => void,
): void {
const pen = getPenById(areaId);
if (!pen) {
return;
}
this.handleAreaSizeChange(pen, findPoints, updateArea);
}
/**
*
*
* @param findAreas
* @param findPoints
* @param updateArea
*/
public checkAndUpdateAllAreas(
findAreas: (type: string) => MapPen[],
findPoints: (type: string) => MapPen[],
updateArea: (id: string, info: Partial<MapAreaInfo>) => void,
): void {
const allAreas = findAreas('area') as MapPen[];
allAreas.forEach((area) => {
if (area.area?.type && [MapAreaType., MapAreaType.].includes(area.area.type)) {
this.handleAreaSizeChange(area, findPoints, updateArea);
}
});
}
}