import { WholeLineAttrib, WholeLineLine, WholeLinePoint, WholeLinePointAttrib, WholeLinePolygonAttrib, } from "../view"; import { KonvaEventObject } from "konva/lib/Node"; import { shapeParentsEq } from "../../../shared"; import { wholeLineAddPoint, wholeLineFixLineAddPoint, wholeLinePolygonLastAddPoint, } from "./whole-line-mouse"; import { Container } from "../../container"; import { Attrib, ShapeType } from "../../../type"; import { WholeLineChange, generateWholeLinePoygonId, getWholeLinePoint, getWholeLinePolygonPoints, mergeChange, wholeLineAddLineByPointIds, wholeLineDelPointByPointIds, } from "./whole-line-base"; import { getAdsorbPosition } from "../../../shared/adsorb"; export type PenWholeLinePoygonsEditProps< P extends Omit > = { tree: Container; config: WholeLineAttrib

; polygonId?: string; adsorbRadius?: number; pointAttribFactory?: (pos: number[]) => Omit; quotePoint?: boolean; canOper?: ( tree: WholeLineLine | WholeLinePoint, operShape: ShapeType ) => boolean; canDelPoint?: (point: P, evt: KonvaEventObject) => boolean; changePolygon?: (polygonId: string) => void; autoClose?: boolean; }; /** * 钢笔模式编辑多边形 * @param polygonId */ export const penWholeLinePoygonsEdit = < P extends Omit >({ tree, config, polygonId, pointAttribFactory, quotePoint, canOper, adsorbRadius, canDelPoint, changePolygon, autoClose, }: PenWholeLinePoygonsEditProps

) => { pointAttribFactory = pointAttribFactory || ((pos: number[]) => ({ x: pos[0], y: pos[1], } as P)); const getPolygonAttrib = (polygonId: string) => { if (!polygonId) { const id = generateWholeLinePoygonId(config); config.polygons.push({ id, lineIds: [], }); return config.polygons[config.polygons.length - 1]; } else { return config.polygons.find(({ id }) => id === polygonId); } }; let polyginAttrib: WholeLinePolygonAttrib; let newMode = false; let prevId: string | null = null; const start = (currentPolygonId: string | null) => { polyginAttrib = getPolygonAttrib(currentPolygonId); if (!polyginAttrib) { throw `${currentPolygonId}的多边形不存在!`; } changePolygon && changePolygon(polyginAttrib.id); polygonId = polyginAttrib.id; newMode = !currentPolygonId; prevId = null; }; start(polygonId); const removePolygon = () => { const ndx = config.polygons.indexOf(polyginAttrib); if (~ndx) { config.polygons.splice(ndx, 1); } }; const continuous = ( evt: KonvaEventObject ): { change: WholeLineChange; isClose?: boolean } => { let change: WholeLineChange = { lineChange: { del: [], update: [], add: [], }, polygonChange: { add: [], update: [], del: [], }, pointChange: { add: [], del: [], }, }; const target = shapeParentsEq(evt.target, (shape) => { const id = shape.id(); return ( id.includes(WholeLineLine.namespace) || id.includes(WholeLinePoint.namespace) ); }); const child = target && tree.find(target.id()); const pixel = [evt.evt.offsetX, evt.evt.offsetY]; if (child instanceof WholeLineLine) { if (!canOper || canOper(child, evt.target)) { if (polyginAttrib.lineIds.includes(child.attrib.id)) { const { change: cChange } = wholeLineFixLineAddPoint( config, child.attrib.id, pointAttribFactory(tree.getRealFromStage(pixel)) ); return { change: mergeChange(change, cChange), isClose: false }; } } } let pointAttrib: P & Attrib; if (child instanceof WholeLinePoint) { if (canOper && !canOper(child, evt.target)) { return { change, isClose: false }; } pointAttrib = quotePoint ? child.attrib : { ...child.attrib }; if (polyginAttrib.id === prevId) { return { change, isClose: false }; } } const polygonPoints = getWholeLinePolygonPoints(config, polyginAttrib.id); if (!pointAttrib) { let position: number[]; if (adsorbRadius) { const points = polygonPoints.map(({ x, y }) => [x, y]); if (prevId) { const prev = getWholeLinePoint(config, prevId); points.push([prev.x, prev.y]); } position = getAdsorbPosition({ tree, pixel, radius: adsorbRadius, points, }); } else { position = tree.getRealFromStage(pixel); } pointAttrib = pointAttribFactory(position) as P & Attrib; } const curNdx = polygonPoints.findIndex(({ id }) => id === pointAttrib.id); const isClose = curNdx === 0 && (!autoClose || polygonPoints.length >= 3); // 存在的情况下删除 if (curNdx >= 0 && !isClose) { const cChange = wholeLineDelPointByPointIds( config, pointAttrib.id, !canDelPoint || canDelPoint(pointAttrib, evt) ); change = mergeChange(change, cChange); if (polyginAttrib.lineIds.length === 0) { removePolygon(); const repPoint = cChange.pointChange.del.find( ({ id }) => id !== pointAttrib.id ); delete repPoint.id; start(null); prevId = wholeLineAddPoint(config, repPoint).id; change.pointChange.add.push({ ...repPoint, id: prevId, }); } return { change, isClose }; } if (!quotePoint) { delete pointAttrib.id; } if (polyginAttrib.lineIds.length > 0) { if (newMode) { const mChange = wholeLinePolygonLastAddPoint( config, polygonId, pointAttrib ).change; // 持续添加模式 return { change: mergeChange(change, mChange), isClose }; } else { // 直接当成新建操作 start(null); return continuous(evt); } } else if (prevId) { const { line, change: mChange } = wholeLineAddLineByPointIds(config, [ prevId, wholeLineAddPoint(config, pointAttrib).id, ]); change = mergeChange(change, mChange, { polygonChange: { update: [ { before: { ...polyginAttrib, lineIds: [...polyginAttrib.lineIds] }, after: { ...polyginAttrib, lineIds: [...polyginAttrib.lineIds, line.id], }, }, ], }, pointChange: { add: [pointAttrib], }, }); polyginAttrib.lineIds.push(line.id); prevId = null; return { change, isClose }; } else { const addPoint = wholeLineAddPoint(config, pointAttrib)!; prevId = addPoint.id; change.pointChange.add.push(addPoint); return { change, isClose }; } }; const end = () => { // 没有两个点以上的多边形直接删除 if (polyginAttrib.lineIds.length === 0) { if (prevId) { wholeLineDelPointByPointIds(config, prevId); } removePolygon(); } changePolygon && changePolygon(null); }; const getStatus = () => ({ newMode, polyginAttribId: polyginAttrib.id, prevId, config, }); return { continuous, end, getStatus, setStatus: (status: ReturnType) => { newMode = status.newMode; polyginAttrib = status.config.polygons.find( ({ id }) => id === status.polyginAttribId ); polygonId = polyginAttrib.id; prevId = status.prevId; config = status.config; }, }; };