marquee-selection 0.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.html +442 -0
- package/README.md +204 -0
- package/dist/index.d.ts +215 -0
- package/dist/infinite-canvas.es.js +475 -0
- package/dist/infinite-canvas.es.js.map +1 -0
- package/dist/infinite-canvas.umd.js +2 -0
- package/dist/infinite-canvas.umd.js.map +1 -0
- package/dist/marquee-selection.es.js +672 -0
- package/dist/marquee-selection.es.js.map +1 -0
- package/dist/marquee-selection.umd.js +2 -0
- package/dist/marquee-selection.umd.js.map +1 -0
- package/index.html +740 -0
- package/package.json +49 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"marquee-selection.es.js","sources":["../src/marqueeSelection.ts"],"sourcesContent":["// 矩形拖拽圈选:在指定容器内,按住鼠标左键拖拽绘制选择框,选中与之相交/包含的子元素\n// 公开一个启用函数,返回用于卸载的 destroy 方法\n\nexport type MarqueeSelectionOptions = {\n // 选择框的父容器,仅在该容器内触发与计算\n container: HTMLElement;\n // 在容器内可被圈选的元素选择器,默认 img\n selectable?: string;\n // 不参与圈选与悬浮高亮的元素(CSS 选择器,单个或数组)。\n // 常见用法:排除 InfiniteCanvas 包裹用的 content 或顶层容器,例如 ['.stage-content', '#container']\n exclude?: string | string[];\n // 选择规则:与框相交 or 完全包含\n selectionMode?: \"intersects\" | \"contains\" | \"center\";\n // 当 selectionMode 为 intersects 时,要求被选中元素与选择框的重叠面积 / 元素自身面积 >= 此阈值(0~1),用于避免轻微擦边命中\n minOverlapRatio?: number;\n // 重叠度计算指标:'element' => 重叠面积/元素面积;'iou' => 交并比,更均衡\n overlapMetric?: \"element\" | \"iou\";\n // 选中样式类名\n selectedClass?: string;\n // 框选变化回调(单选/编组)\n onChange?: (\n payload:\n | { type: \"single\"; selected: Element[] }\n | { type: \"groups\"; groups: Element[][]; flat: Element[] }\n ) => void;\n // 如果一个元素和其后代都命中,是否移除祖先,仅保留叶子节点(默认 true,避免选中大父容器)\n preventAncestorSelection?: boolean;\n // 父子同时命中时的冲突处理:\n // - 'none' 不处理(父子并存)\n // - 'leaf' 仅保留叶子(等同 preventAncestorSelection=true)\n // - 'best' 每条祖先链保留得分更高者(推荐)\n conflictStrategy?: \"none\" | \"leaf\" | \"best\";\n // 多次圈选:是否累积选择(默认 false)。true 时本次拖拽将与已有选择集合合并。\n multi?: boolean;\n // 多次圈选合并模式:\n // - 'replace' 仅保留本次命中\n // - 'add' 将本次命中加入已有集合\n // - 'subtract'从已有集合移除本次命中\n // - 'toggle' 对本次命中做切换(有则去,无则加)\n // - 'auto' 根据按键:Shift=add,Alt=subtract,Meta/Ctrl=toggle,默认 add\n combineMode?: \"replace\" | \"add\" | \"subtract\" | \"toggle\" | \"auto\";\n // 编组模式:每次 mouseup 将本次命中作为一组,并渲染组外框\n groupMode?: boolean;\n // 组外框类名(可自定义样式),默认使用内联样式\n groupOverlayClass?: string;\n // 组主题颜色:用于组外框描边与工具栏背景。\n // - 若提供字符串,则所有组使用该颜色(如 '#3b82f6' / 'hsl(215,90%,57%)' / 'rgba(59,130,246,.9)')。\n // - 若不提供且 groupRandomColor=true,则为每个新组随机生成一个柔和色。\n // - 也可提供 groupColorPalette 与 groupRandomColor 搭配使用。\n groupColor?: string;\n // 是否为每个新组随机生成颜色(默认 false)。\n groupRandomColor?: boolean;\n // 随机/轮换可选调色板(提供时将优先从此列表取色;否则使用内置的柔和色生成)。\n groupColorPalette?: string[];\n // 是否启用鼠标悬浮高亮(默认 false)\n hoverHighlight?: boolean;\n // 悬浮高亮类名(默认 'hovered')\n hoverClass?: string;\n // 拖拽结束回调:返回一次完整快照(等价于 controller.getSelectionResult() 的值)\n onSelectionEnd?: (snapshot: MarqueeSelectionSnapshot) => void;\n // 双击快速成组:双击元素时,以其外框为选择区域,快速生成一组(默认 false)\n quickGroupOnDblClick?: boolean;\n // 双击触发元素的筛选选择器(可选)。若提供,则仅当双击目标的最近祖先匹配该选择器时才触发;\n // 未提供时,使用双击目标元素自身。\n quickGroupSelector?: string;\n // 是否支持“交集圈选”(默认 true)。false 则新组与已有选择的元素集合不能有交集;\n // 注意:交集与“并集模式”不同,禁用交集不影响并集聚合能力。\n allowIntersectionSelection?: boolean;\n // 当 allowIntersectionSelection = false 时,是否仍允许“完全包含”关系(父子):\n // 即命中集合是现有集合的子集/父集(不属于部分交叉)。默认 true 允许,仅禁止“部分相交”。\n // 设为 false 则同样禁止包含关系(仅允许完全不相交或完全相等)。\n allowContainmentSelection?: boolean;\n // 是否支持“并集圈选”(默认 true)。false 则在已有选择存在时,禁止新增圈选(包括与其相交或包含的情况)。\n allowUnionSelection?: boolean;\n // 自定义工具栏按钮:会追加到每个组的工具栏\n toolbarButtons?: Array<{\n label: string; // 按钮文本\n title?: string; // 鼠标提示\n className?: string; // 附加类名\n onClick?: (ctx: {\n index: number; // 组索引\n group: Element[]; // 该组元素\n controller: MarqueeSelectionController; // 控制器\n getSnapshot: () => MarqueeSelectionSnapshot; // 获取最新快照\n refresh: () => void; // 触发重绘覆盖层并广播 onSelectionEnd\n mouseX?: number; // 触发点击时的鼠标 X(client)\n mouseY?: number; // 触发点击时的鼠标 Y(client)\n anchorRect?: DOMRect; // 工具栏矩形(可用于定位)\n anchorEl?: HTMLElement; // 工具栏元素\n overlayEl?: HTMLElement; // 覆盖层元素\n }) => void;\n }>;\n};\n\nexport type MarqueeSelectionSnapshot =\n | { type: \"single\"; selected: Element[] }\n | {\n type: \"groups\";\n groups: Element[][];\n flat: Element[];\n hidden: boolean[];\n groupRects: ({\n left: number;\n top: number;\n width: number;\n height: number;\n } | null)[];\n // 组级嵌套(按组外接矩形包含关系)\n groupNesting: {\n parents: (number | null)[]; // 每个组的最近父组索引(若无则为 null)\n children: number[][]; // 每个组的直接子组索引列表\n roots: number[]; // 无父组的组索引\n };\n };\n\nexport type MarqueeSelectionController = {\n destroy: () => void;\n getGroups: () => Element[][];\n clearGroups: () => void;\n removeGroup: (index: number) => boolean;\n // 编程式新增一组:将给定元素集合加入为新组(仅在 groupMode 下有效)。\n // 返回值:true 表示创建成功;false 表示因配置限制/重复/无效元素而未创建。\n addGroup: (elements: Element[]) => boolean;\n setGroupVisibility: (index: number, hidden: boolean) => boolean;\n toggleGroupVisibility: (index: number) => boolean;\n getSelectionResult: () => MarqueeSelectionSnapshot;\n // 仅重绘覆盖层(适用于外部视图变换后刷新)\n refresh: () => void;\n // 隐藏覆盖层(用于进行视图变换时临时隐藏)\n hideOverlays: () => void;\n // 显示并重绘覆盖层(变换结束后调用)\n showAndRefreshOverlays: () => void;\n // 订阅下一次拖拽结束(持续订阅)\n onSelectionEnd: (\n handler: (snapshot: MarqueeSelectionSnapshot) => void\n ) => () => void;\n // 等待下一次拖拽结束(一次性)\n waitForSelectionEnd: () => Promise<MarqueeSelectionSnapshot>;\n // 获取当前组级嵌套信息(仅 groupMode 下有效,其他返回 null)\n getGroupNesting: () => {\n parents: (number | null)[];\n children: number[][];\n roots: number[];\n } | null;\n};\n\n/**\n * 启用容器内矩形拖拽圈选\n */\nexport function marqueeSelection(\n options: MarqueeSelectionOptions\n): MarqueeSelectionController {\n const {\n container,\n selectable = \"img\",\n exclude,\n selectionMode = \"intersects\",\n minOverlapRatio = 0,\n overlapMetric = \"element\",\n selectedClass = \"selected\",\n onChange,\n preventAncestorSelection = true,\n conflictStrategy,\n groupMode = false,\n groupOverlayClass,\n groupColor,\n groupRandomColor = false,\n groupColorPalette,\n multi = false,\n combineMode,\n hoverHighlight = false,\n hoverClass = \"hovered\",\n onSelectionEnd: onSelectionEndOption,\n quickGroupOnDblClick = false,\n quickGroupSelector,\n allowIntersectionSelection = true,\n allowUnionSelection = true,\n allowContainmentSelection = true,\n toolbarButtons,\n } = options;\n // 归一化排除选择器\n const excludeSelectors: string[] = Array.isArray(exclude)\n ? (exclude.filter(Boolean) as string[])\n : exclude\n ? [exclude]\n : [];\n const isExcluded = (el: Element | null | undefined): boolean => {\n if (!el || !excludeSelectors.length) return false;\n for (const sel of excludeSelectors) {\n try {\n if (el instanceof Element && el.matches(sel)) return true;\n } catch {}\n }\n return false;\n };\n\n if (!container) throw new Error(\"container is required\");\n\n // 内部状态\n let startX = 0;\n let startY = 0;\n let isDragging = false;\n let marqueeEl: HTMLDivElement | null = null;\n let dragInvalid = false; // 当前拖拽是否因配置被判定为无效(红框提示)\n // 已应用到 DOM 的当前选择集合\n let selectedSet = new Set<Element>();\n // 当前拖拽前的基线集合(用于多次圈选)\n let baseSet: Set<Element> | null = null;\n // 当前拖拽的合并模式\n let dragCombine: \"replace\" | \"add\" | \"subtract\" | \"toggle\" = \"replace\";\n // 编组数据与覆盖层\n let groups: Element[][] = [];\n let groupOverlays: HTMLDivElement[] = [];\n // 组可见性状态\n let groupHidden: boolean[] = [];\n // 组主题颜色(与 groups 等长)\n let groupColors: string[] = [];\n\n // 获取一个新组的主题色\n const pickPastel = () => {\n const h = Math.floor(Math.random() * 360);\n const s = 70;\n const l = 55;\n return `hsl(${h}, ${s}%, ${l}%)`;\n };\n const getNewGroupColor = (): string => {\n if (groupColor && typeof groupColor === \"string\")\n return groupColor as string;\n if (groupRandomColor) {\n if (Array.isArray(groupColorPalette) && groupColorPalette.length > 0) {\n const idx = Math.floor(Math.random() * groupColorPalette.length);\n return groupColorPalette[idx]!;\n }\n return pickPastel();\n }\n return \"rgba(255, 165, 0, 0.9)\";\n };\n // 最近一次新建的组索引(用于显示合并按钮)\n let lastCreatedGroupIndex: number | null = null;\n // 拖拽结束事件\n const endListeners: Array<(s: MarqueeSelectionSnapshot) => void> = [];\n const endWaiters: Array<(s: MarqueeSelectionSnapshot) => void> = [];\n // 组框调整尺寸会话\n type ResizeSide =\n | \"left\"\n | \"right\"\n | \"top\"\n | \"bottom\"\n | \"nw\"\n | \"ne\"\n | \"sw\"\n | \"se\";\n let resizeSession: null | {\n idx: number;\n side: ResizeSide;\n startX: number;\n startY: number;\n startRect: { left: number; top: number; width: number; height: number };\n overlay: HTMLDivElement;\n } = null;\n // 判断命中元素是否与已存在的某个组完全一致,返回组索引或 null\n const findDuplicateGroupIndex = (els: Element[]): number | null => {\n if (!els.length) return null;\n const target = new Set<Element>(els);\n for (let i = 0; i < groups.length; i++) {\n const g = groups[i] || [];\n if (g.length !== target.size) continue;\n let same = true;\n // 将当前组转为集合便于比较\n const gs = new Set<Element>(g);\n if (gs.size !== target.size) {\n same = false;\n }\n if (same) {\n for (const el of target) {\n if (!gs.has(el)) {\n same = false;\n break;\n }\n }\n }\n if (same) return i;\n }\n return null;\n };\n\n // 提前声明控制器引用,便于在内部回调中访问\n let controllerRef: MarqueeSelectionController | null = null;\n\n const applyGroupVisibility = (index: number) => {\n const hidden = !!groupHidden[index];\n const els = groups[index] || [];\n for (const el of els) {\n (el as HTMLElement).style.visibility = hidden ? \"hidden\" : \"\";\n }\n };\n\n const setGroupHidden = (index: number, hidden: boolean) => {\n if (index < 0 || index >= groups.length) return false;\n groupHidden[index] = hidden;\n applyGroupVisibility(index);\n return true;\n };\n // 悬浮高亮\n let hoveredEl: Element | null = null;\n\n const setHovered = (el: Element | null) => {\n if (!hoverHighlight) return;\n if (hoveredEl && hoveredEl !== el) {\n hoveredEl.classList.remove(hoverClass);\n }\n if (el && hoveredEl !== el) {\n el.classList.add(hoverClass);\n }\n hoveredEl = el;\n };\n\n // 创建并样式化选择框(添加到 body,避免容器 overflow 或层级影响)\n const createMarquee = () => {\n const el = document.createElement(\"div\");\n el.style.position = \"fixed\";\n el.style.left = \"0px\";\n el.style.top = \"0px\";\n el.style.width = \"0px\";\n el.style.height = \"0px\";\n el.style.outline = \"1px dashed #268aff\";\n el.style.background = \"rgba(38,138,255,0.12)\";\n el.style.pointerEvents = \"none\";\n el.style.zIndex = \"2147483647\"; // 置顶\n el.style.boxSizing = \"border-box\";\n document.body.appendChild(el);\n return el;\n };\n\n // 工具:计算两个矩形是否相交/包含\n const rectIntersects = (a: DOMRect, b: DOMRect) =>\n a.left < b.right &&\n a.right > b.left &&\n a.top < b.bottom &&\n a.bottom > b.top;\n const rectContains = (outer: DOMRect, inner: DOMRect) =>\n outer.left <= inner.left &&\n outer.right >= inner.right &&\n outer.top <= inner.top &&\n outer.bottom >= inner.bottom;\n\n // 重叠面积 / 元素面积\n const overlapRatio = (a: DOMRect, b: DOMRect): number => {\n const left = Math.max(a.left, b.left);\n const right = Math.min(a.right, b.right);\n const top = Math.max(a.top, b.top);\n const bottom = Math.min(a.bottom, b.bottom);\n const w = Math.max(0, right - left);\n const h = Math.max(0, bottom - top);\n const overlap = w * h;\n const areaB = Math.max(1, b.width * b.height); // 避免除 0\n return overlap / areaB;\n };\n\n // IoU:重叠面积 / 并集面积\n const iouRatio = (a: DOMRect, b: DOMRect): number => {\n const left = Math.max(a.left, b.left);\n const right = Math.min(a.right, b.right);\n const top = Math.max(a.top, b.top);\n const bottom = Math.min(a.bottom, b.bottom);\n const w = Math.max(0, right - left);\n const h = Math.max(0, bottom - top);\n const inter = w * h;\n const areaA = Math.max(1, a.width * a.height);\n const areaB = Math.max(1, b.width * b.height);\n const union = areaA + areaB - inter;\n return inter / union;\n };\n\n const getRatio = (marqueeRect: DOMRect, elementRect: DOMRect): number =>\n overlapMetric === \"iou\"\n ? iouRatio(marqueeRect, elementRect)\n : overlapRatio(marqueeRect, elementRect);\n\n // 工具:获取当前选择框 rect(基于 client 坐标)\n const getCurrentMarqueeRect = (\n x1: number,\n y1: number,\n x2: number,\n y2: number\n ): { left: number; top: number; width: number; height: number } => {\n const left = Math.min(x1, x2);\n const top = Math.min(y1, y2);\n const width = Math.abs(x2 - x1);\n const height = Math.abs(y2 - y1);\n return { left, top, width, height };\n };\n\n // 组外框计算与渲染\n const calcGroupRect = (\n els: Element[]\n ): { left: number; top: number; width: number; height: number } | null => {\n const rects = els\n .map((el) => el.getBoundingClientRect())\n .filter((r) => r.width > 0 && r.height > 0);\n if (!rects.length) return null;\n const left = Math.min(...rects.map((r) => r.left));\n const top = Math.min(...rects.map((r) => r.top));\n const right = Math.max(...rects.map((r) => r.right));\n const bottom = Math.max(...rects.map((r) => r.bottom));\n return { left, top, width: right - left, height: bottom - top };\n };\n\n const clearGroupOverlays = () => {\n groupOverlays.forEach((el) => el.remove());\n groupOverlays = [];\n };\n\n const renderGroupOverlays = () => {\n clearGroupOverlays();\n if (!groupMode) return;\n // 已放置的工具栏矩形(用于避让)\n const placedToolbarRects: Array<{\n left: number;\n top: number;\n right: number;\n bottom: number;\n }> = [];\n const rectsOverlap = (\n a: { left: number; top: number; right: number; bottom: number },\n b: { left: number; top: number; right: number; bottom: number }\n ) =>\n a.left < b.right &&\n a.right > b.left &&\n a.top < b.bottom &&\n a.bottom > b.top;\n\n groups.forEach((g, idx) => {\n const box = calcGroupRect(g);\n if (!box) return;\n const color = groupColors[idx] || \"rgba(255, 165, 0, 0.9)\";\n const el = document.createElement(\"div\");\n el.style.position = \"fixed\";\n el.style.pointerEvents = \"none\"; // 覆盖层本体不拦截,下面的工具条与句柄可交互\n el.style.zIndex = \"2147483646\";\n el.style.left = `${box.left}px`;\n el.style.top = `${box.top}px`;\n el.style.width = `${box.width}px`;\n el.style.height = `${box.height}px`;\n el.style.boxSizing = \"border-box\";\n el.style.outline = `1px solid ${color}`;\n el.style.background = \"transparent\";\n // 先挂载到 DOM,便于测量内部工具栏尺寸与布局\n document.body.appendChild(el);\n // 工具条(可交互),置于标签位置\n const toolbar = document.createElement(\"div\");\n toolbar.style.position = \"absolute\";\n // 初始位置将由 placeToolbar 决定\n toolbar.style.display = \"inline-flex\";\n toolbar.style.alignItems = \"center\";\n toolbar.style.gap = \"6px\";\n // 优化:避免工具栏过宽撑破容器\n toolbar.style.minWidth = \"max-content\";\n toolbar.style.padding = \"2px 6px\";\n toolbar.style.fontSize = \"12px\";\n toolbar.style.lineHeight = \"16px\";\n toolbar.style.color = \"#fff\";\n toolbar.style.background = color;\n toolbar.style.borderRadius = \"4px\";\n toolbar.style.pointerEvents = \"auto\"; // 工具条可点\n\n const label = document.createElement(\"span\");\n label.textContent = `组 ${idx + 1}`;\n\n const toggleBtn = document.createElement(\"button\");\n toggleBtn.textContent = groupHidden[idx] ? \"显示\" : \"隐藏\";\n toggleBtn.style.background = \"rgba(0,0,0,0.15)\";\n toggleBtn.style.border = \"none\";\n toggleBtn.style.color = \"#fff\";\n toggleBtn.style.padding = \"2px 6px\";\n toggleBtn.style.borderRadius = \"3px\";\n toggleBtn.style.cursor = \"pointer\";\n toggleBtn.onclick = (ev) => {\n ev.stopPropagation();\n setGroupHidden(idx, !groupHidden[idx]);\n renderGroupOverlays(); // 刷新按钮文案\n // 通知外部:可用于刷新结果面板(hidden 状态改变)\n notifySelectionEnd();\n };\n\n const removeBtn = document.createElement(\"button\");\n removeBtn.textContent = \"取消组\";\n removeBtn.style.background = \"rgba(0,0,0,0.15)\";\n removeBtn.style.border = \"none\";\n removeBtn.style.color = \"#fff\";\n removeBtn.style.padding = \"2px 6px\";\n removeBtn.style.borderRadius = \"3px\";\n removeBtn.style.cursor = \"pointer\";\n removeBtn.onclick = (ev) => {\n ev.stopPropagation();\n // 移除前恢复可见,避免遗留隐藏样式\n setGroupHidden(idx, false);\n removeGroupAt(idx);\n };\n\n toolbar.appendChild(label);\n toolbar.appendChild(toggleBtn);\n toolbar.appendChild(removeBtn);\n\n // 若该组为最近创建,且与其他组发生矩形相交,则显示“合并”按钮\n const getIntersectingIndices = (selfIdx: number): number[] => {\n const selfRect = box\n ? new DOMRect(box.left, box.top, box.width, box.height)\n : null;\n if (!selfRect) return [];\n const list: number[] = [];\n groups.forEach((og, j) => {\n if (j === selfIdx) return;\n const ob = calcGroupRect(og);\n if (!ob) return;\n const orect = new DOMRect(ob.left, ob.top, ob.width, ob.height);\n if (rectIntersects(selfRect, orect)) list.push(j);\n });\n return list;\n };\n\n const maybeAddMergeButton = () => {\n if (lastCreatedGroupIndex !== idx) return;\n const ints = getIntersectingIndices(idx);\n if (ints.length === 0) return;\n const mergeBtn = document.createElement(\"button\");\n mergeBtn.textContent = \"合并\";\n mergeBtn.style.background = \"rgba(0,0,0,0.15)\";\n mergeBtn.style.border = \"none\";\n mergeBtn.style.color = \"#fff\";\n mergeBtn.style.padding = \"2px 6px\";\n mergeBtn.style.borderRadius = \"3px\";\n mergeBtn.style.cursor = \"pointer\";\n\n const openPanel = () => {\n // 如果已存在面板,先移除\n const old = toolbar.querySelector(\".merge-panel\");\n if (old) old.remove();\n const panel = document.createElement(\"div\");\n panel.className = \"merge-panel\";\n panel.style.position = \"absolute\";\n panel.style.left = \"0\";\n panel.style.top = \"22px\"; // 工具条下方\n panel.style.minWidth = \"160px\";\n panel.style.padding = \"8px\";\n panel.style.background = \"#fff\";\n panel.style.color = \"#333\";\n panel.style.border = \"1px solid rgba(0,0,0,0.15)\";\n panel.style.borderRadius = \"6px\";\n panel.style.boxShadow = \"0 4px 12px rgba(0,0,0,0.15)\";\n panel.style.pointerEvents = \"auto\";\n panel.style.zIndex = \"2147483647\";\n\n const title = document.createElement(\"div\");\n title.textContent = \"选择要合并的组\";\n title.style.fontSize = \"12px\";\n title.style.marginBottom = \"6px\";\n panel.appendChild(title);\n\n const listWrap = document.createElement(\"div\");\n listWrap.style.maxHeight = \"200px\";\n listWrap.style.overflow = \"auto\";\n const checkboxRefs: HTMLInputElement[] = [];\n ints.forEach((j) => {\n const row = document.createElement(\"label\");\n row.style.display = \"flex\";\n row.style.alignItems = \"center\";\n row.style.gap = \"6px\";\n row.style.fontSize = \"12px\";\n row.style.margin = \"4px 0\";\n const cb = document.createElement(\"input\");\n cb.type = \"checkbox\";\n cb.checked = true;\n cb.value = String(j);\n const txt = document.createElement(\"span\");\n txt.textContent = `组 ${j + 1}`;\n row.appendChild(cb);\n row.appendChild(txt);\n listWrap.appendChild(row);\n checkboxRefs.push(cb);\n });\n panel.appendChild(listWrap);\n\n const actions = document.createElement(\"div\");\n actions.style.display = \"flex\";\n actions.style.gap = \"8px\";\n actions.style.marginTop = \"8px\";\n const ok = document.createElement(\"button\");\n ok.textContent = \"确认\";\n ok.style.padding = \"2px 8px\";\n ok.style.cursor = \"pointer\";\n const cancel = document.createElement(\"button\");\n cancel.textContent = \"取消\";\n cancel.style.padding = \"2px 8px\";\n cancel.style.cursor = \"pointer\";\n actions.appendChild(ok);\n actions.appendChild(cancel);\n panel.appendChild(actions);\n\n cancel.onclick = (ev) => {\n ev.stopPropagation();\n panel.remove();\n };\n ok.onclick = (ev) => {\n ev.stopPropagation();\n const chosen = checkboxRefs\n .filter((c) => c.checked)\n .map((c) => parseInt(c.value, 10))\n .filter((n) => !Number.isNaN(n));\n if (chosen.length === 0) {\n panel.remove();\n return;\n }\n // 合并逻辑:将选中组与当前组求并集,替换当前组,并移除被合并的组\n const union = new Set<Element>();\n const base = groups[idx] || [];\n base.forEach((el) => union.add(el));\n chosen.forEach((ci) => {\n const arr = groups[ci] || [];\n arr.forEach((el) => union.add(el));\n });\n groups[idx] = Array.from(union);\n // 被合并组若处于隐藏,先恢复可见再删除\n const sorted = [...chosen].sort((a, b) => b - a);\n let newIdx = idx;\n sorted.forEach((ri) => {\n if (ri < 0 || ri >= groups.length || ri === idx) return;\n setGroupHidden(ri, false);\n groups.splice(ri, 1);\n groupHidden.splice(ri, 1);\n groupColors.splice(ri, 1);\n if (lastCreatedGroupIndex !== null) {\n if (lastCreatedGroupIndex === ri) lastCreatedGroupIndex = null;\n else if (lastCreatedGroupIndex > ri) lastCreatedGroupIndex--;\n }\n if (ri < newIdx) newIdx--;\n });\n // 合并结果保留在(调整后的)当前组位置,并作为“最近创建”以便继续合并\n lastCreatedGroupIndex = newIdx;\n // 刷新 UI 与选择\n const unionSel = new Set<Element>();\n groups.forEach((g) => g.forEach((el) => unionSel.add(el)));\n updateDomSelection(unionSel);\n renderGroupOverlays();\n panel.remove();\n notifySelectionEnd();\n };\n\n toolbar.appendChild(panel);\n };\n\n mergeBtn.onclick = (ev) => {\n ev.stopPropagation();\n openPanel();\n };\n toolbar.appendChild(mergeBtn);\n };\n maybeAddMergeButton();\n el.appendChild(toolbar);\n\n // 追加自定义工具栏按钮\n if (toolbarButtons && toolbarButtons.length) {\n const addCustomButton = (\n cfg: NonNullable<MarqueeSelectionOptions[\"toolbarButtons\"]>[number]\n ) => {\n const btn = document.createElement(\"button\");\n btn.textContent = cfg.label || \"按钮\";\n btn.title = cfg.title || \"\";\n btn.style.background = \"rgba(0,0,0,0.15)\";\n btn.style.border = \"none\";\n btn.style.color = \"#fff\";\n btn.style.padding = \"2px 6px\";\n btn.style.borderRadius = \"3px\";\n btn.style.cursor = \"pointer\";\n if (cfg.className)\n btn.className += (btn.className ? \" \" : \"\") + cfg.className;\n btn.onclick = (ev) => {\n ev.stopPropagation();\n try {\n cfg.onClick?.({\n index: idx,\n group: groups[idx] || [],\n controller: controllerRef as MarqueeSelectionController,\n getSnapshot: () => buildSnapshot(),\n refresh: () => {\n renderGroupOverlays();\n notifySelectionEnd();\n },\n mouseX: (ev as MouseEvent).clientX,\n mouseY: (ev as MouseEvent).clientY,\n anchorRect: toolbar.getBoundingClientRect(),\n anchorEl: toolbar,\n overlayEl: el,\n });\n } catch {}\n };\n toolbar.appendChild(btn);\n };\n toolbarButtons.forEach(addCustomButton);\n }\n\n // 工具:将工具栏放置到避免重叠的位置(尝试四角 + 台阶偏移)\n const placeToolbar = () => {\n const anchors: Array<\"tl\" | \"tr\" | \"bl\" | \"br\"> = [\n \"tl\",\n \"tr\",\n \"bl\",\n \"br\",\n ];\n // 隐藏以避免闪烁\n const prevVisibility = toolbar.style.visibility;\n toolbar.style.visibility = \"hidden\";\n const step = 28; // 纵向台阶高度\n const margin = 6; // 与外框的间距\n // 尝试不同锚点 + 若干台阶偏移\n outer: for (let a = 0; a < anchors.length; a++) {\n for (let k = 0; k < 6; k++) {\n // 重置定位\n toolbar.style.left = \"\";\n toolbar.style.right = \"\";\n toolbar.style.top = \"\";\n toolbar.style.bottom = \"\";\n const h = toolbar.offsetHeight || 22;\n if (anchors[a] === \"tl\") {\n toolbar.style.left = \"0\";\n toolbar.style.top = `${-h - margin + k * step}px`;\n } else if (anchors[a] === \"tr\") {\n toolbar.style.right = \"0\";\n toolbar.style.top = `${-h - margin + k * step}px`;\n } else if (anchors[a] === \"bl\") {\n toolbar.style.left = \"0\";\n toolbar.style.top = `${box.height + margin + k * step}px`;\n } else {\n toolbar.style.right = \"0\";\n toolbar.style.top = `${box.height + margin + k * step}px`;\n }\n const r = toolbar.getBoundingClientRect();\n const rect = {\n left: r.left,\n top: r.top,\n right: r.right,\n bottom: r.bottom,\n };\n // 不再基于视口上边界进行约束检查,允许工具栏在可见区域之外放置(与 AI 浮层一致)\n // 与已放置的工具栏避免重叠\n let collide = false;\n for (const pr of placedToolbarRects) {\n if (rectsOverlap(rect, pr)) {\n collide = true;\n break;\n }\n }\n if (!collide) {\n placedToolbarRects.push(rect);\n break outer;\n }\n }\n }\n toolbar.style.visibility = prevVisibility;\n };\n placeToolbar();\n\n // 悬停工具条将对应覆盖层置顶,便于在重叠场景下切换\n toolbar.addEventListener(\"mouseenter\", () => {\n try {\n groupOverlays.forEach((ov) => (ov.style.zIndex = \"2147483646\"));\n el.style.zIndex = \"2147483647\";\n } catch {}\n });\n\n // 边缘与四角拖拽句柄\n const addHandle = (side: ResizeSide) => {\n const h = document.createElement(\"div\");\n h.style.position = \"absolute\";\n h.style.pointerEvents = \"auto\";\n h.style.background = \"transparent\";\n h.style.zIndex = \"2147483647\";\n const thickness = 8; // 命中区域\n if (side === \"top\") {\n h.style.cursor = \"ns-resize\";\n h.style.left = \"-4px\";\n h.style.right = \"-4px\";\n h.style.top = `-${(thickness / 2) | 0}px`;\n h.style.height = `${thickness}px`;\n } else if (side === \"bottom\") {\n h.style.cursor = \"ns-resize\";\n h.style.left = \"-4px\";\n h.style.right = \"-4px\";\n h.style.bottom = `-${(thickness / 2) | 0}px`;\n h.style.height = `${thickness}px`;\n } else if (side === \"left\") {\n h.style.cursor = \"ew-resize\";\n h.style.top = \"-4px\";\n h.style.bottom = \"-4px\";\n h.style.left = `-${(thickness / 2) | 0}px`;\n h.style.width = `${thickness}px`;\n } else if (side === \"right\") {\n h.style.cursor = \"ew-resize\";\n h.style.top = \"-4px\";\n h.style.bottom = \"-4px\";\n h.style.right = `-${(thickness / 2) | 0}px`;\n h.style.width = `${thickness}px`;\n } else if (side === \"nw\") {\n h.style.cursor = \"nwse-resize\";\n h.style.left = `-${(thickness / 2) | 0}px`;\n h.style.top = `-${(thickness / 2) | 0}px`;\n h.style.width = `${thickness}px`;\n h.style.height = `${thickness}px`;\n } else if (side === \"ne\") {\n h.style.cursor = \"nesw-resize\";\n h.style.right = `-${(thickness / 2) | 0}px`;\n h.style.top = `-${(thickness / 2) | 0}px`;\n h.style.width = `${thickness}px`;\n h.style.height = `${thickness}px`;\n } else if (side === \"sw\") {\n h.style.cursor = \"nesw-resize\";\n h.style.left = `-${(thickness / 2) | 0}px`;\n h.style.bottom = `-${(thickness / 2) | 0}px`;\n h.style.width = `${thickness}px`;\n h.style.height = `${thickness}px`;\n } else if (side === \"se\") {\n h.style.cursor = \"nwse-resize\";\n h.style.right = `-${(thickness / 2) | 0}px`;\n h.style.bottom = `-${(thickness / 2) | 0}px`;\n h.style.width = `${thickness}px`;\n h.style.height = `${thickness}px`;\n }\n h.onmousedown = (ev) => {\n ev.preventDefault();\n ev.stopPropagation();\n // 启动调整会话\n const rect = {\n left: parseFloat(el.style.left || \"0\"),\n top: parseFloat(el.style.top || \"0\"),\n width: parseFloat(el.style.width || \"0\"),\n height: parseFloat(el.style.height || \"0\"),\n };\n resizeSession = {\n idx,\n side,\n startX: (ev as MouseEvent).clientX,\n startY: (ev as MouseEvent).clientY,\n startRect: rect,\n overlay: el,\n };\n document.addEventListener(\"mousemove\", onResizeMove);\n document.addEventListener(\"mouseup\", onResizeEnd, { once: true });\n };\n el.appendChild(h);\n };\n // 四边\n addHandle(\"top\");\n addHandle(\"right\");\n addHandle(\"bottom\");\n addHandle(\"left\");\n // 四角\n addHandle(\"nw\");\n addHandle(\"ne\");\n addHandle(\"sw\");\n addHandle(\"se\");\n\n if (groupOverlayClass) el.classList.add(groupOverlayClass);\n groupOverlays.push(el);\n });\n };\n\n const onResizeMove = (e: MouseEvent) => {\n if (!resizeSession) return;\n const { idx, side, startX, startY, startRect, overlay } = resizeSession;\n const dx = e.clientX - startX;\n const dy = e.clientY - startY;\n let left = startRect.left;\n let top = startRect.top;\n let width = startRect.width;\n let height = startRect.height;\n const minSize = 4;\n if (side === \"left\" || side === \"nw\" || side === \"sw\") {\n left = startRect.left + dx;\n width = startRect.width - dx;\n if (width < minSize) {\n left = startRect.left + (startRect.width - minSize);\n width = minSize;\n }\n } else if (side === \"right\" || side === \"ne\" || side === \"se\") {\n width = startRect.width + dx;\n if (width < minSize) width = minSize;\n }\n if (side === \"top\" || side === \"nw\" || side === \"ne\") {\n top = startRect.top + dy;\n height = startRect.height - dy;\n if (height < minSize) {\n top = startRect.top + (startRect.height - minSize);\n height = minSize;\n }\n } else if (side === \"bottom\" || side === \"sw\" || side === \"se\") {\n height = startRect.height + dy;\n if (height < minSize) height = minSize;\n }\n // 更新覆盖层位置(预览区域)\n overlay.style.left = `${left}px`;\n overlay.style.top = `${top}px`;\n overlay.style.width = `${width}px`;\n overlay.style.height = `${height}px`;\n\n // 计算并实时预览该组的新命中(带约束校验)\n const hits = computeSelection(left, top, width, height);\n const currentSet = new Set<Element>(groups[idx] || []);\n const otherSet = new Set<Element>();\n groups.forEach((g, i) => {\n if (i !== idx) g.forEach((el) => otherSet.add(el));\n });\n const hitsSet = new Set<Element>(hits);\n let partialOverlapFound = false;\n let containmentFound = false; // 命中集合与某个其它组构成包含关系\n for (let i = 0; i < groups.length; i++) {\n if (i === idx) continue;\n const gSet = new Set<Element>(groups[i] || []);\n let interCount = 0;\n for (const el of hitsSet) if (gSet.has(el)) interCount++;\n if (interCount === 0) continue; // 不相交\n if (interCount === gSet.size && interCount === hitsSet.size) {\n // 完全相等 -> 视为允许(重复在其它地方处理)\n continue;\n } else if (interCount === gSet.size) {\n // 其它组完全在 hits 内\n containmentFound = true;\n } else if (interCount === hitsSet.size) {\n // hits 完全在其它组内\n containmentFound = true;\n } else {\n partialOverlapFound = true;\n break;\n }\n }\n const deltaAddCount = hits.filter((el) => !currentSet.has(el)).length;\n const violatesIntersection = !allowIntersectionSelection && (\n partialOverlapFound ||\n (!allowContainmentSelection && containmentFound)\n );\n const violatesUnion = !allowUnionSelection && deltaAddCount > 0; // 禁并集:禁止新增元素(允许减少)\n const invalid = violatesIntersection || violatesUnion;\n\n // 预览与提示:无效则保持原组不变,边框红色;有效则以 hits 预览,边框为正常橙色\n if (invalid) {\n overlay.style.outline = \"1px dashed #ff4d4f\";\n overlay.style.background = \"rgba(255,77,79,0.06)\";\n const union = new Set<Element>();\n groups.forEach((g, i) => {\n const arr = i === idx ? groups[idx] || [] : g; // 不应用 hits\n arr.forEach((el) => union.add(el));\n });\n updateDomSelection(union);\n } else {\n const color = groupColors[idx] || \"rgba(255, 165, 0, 0.9)\";\n overlay.style.outline = `1px solid ${color}`;\n overlay.style.background = \"transparent\";\n const union = new Set<Element>();\n groups.forEach((g, i) => {\n const arr = i === idx ? hits : g;\n arr.forEach((el) => union.add(el));\n });\n updateDomSelection(union);\n }\n };\n\n const onResizeEnd = (e: MouseEvent) => {\n if (!resizeSession) return;\n const { idx, overlay, startRect } =\n resizeSession as typeof resizeSession & {\n startRect: { left: number; top: number; width: number; height: number };\n };\n // 以当前 overlay 矩形为准,计算最终组命中\n const left = parseFloat(overlay.style.left || \"0\");\n const top = parseFloat(overlay.style.top || \"0\");\n const width = parseFloat(overlay.style.width || \"0\");\n const height = parseFloat(overlay.style.height || \"0\");\n const hits = computeSelection(left, top, width, height);\n // 约束校验:与其它组的交/并限制\n const currentSet = new Set<Element>(groups[idx] || []);\n const otherSet = new Set<Element>();\n groups.forEach((g, i) => {\n if (i !== idx) g.forEach((el) => otherSet.add(el));\n });\n const hitsSet = new Set<Element>(hits);\n let partialOverlapFound = false;\n let containmentFound = false;\n for (let i = 0; i < groups.length; i++) {\n if (i === idx) continue;\n const gSet = new Set<Element>(groups[i] || []);\n let interCount = 0;\n for (const el of hitsSet) if (gSet.has(el)) interCount++;\n if (interCount === 0) continue;\n if (interCount === gSet.size && interCount === hitsSet.size) {\n continue; // equal\n } else if (interCount === gSet.size || interCount === hitsSet.size) {\n containmentFound = true;\n } else {\n partialOverlapFound = true;\n break;\n }\n }\n const deltaAddCount = hits.filter((el) => !currentSet.has(el)).length;\n const violatesIntersection = !allowIntersectionSelection && (\n partialOverlapFound ||\n (!allowContainmentSelection && containmentFound)\n );\n const violatesUnion = !allowUnionSelection && deltaAddCount > 0; // 禁并集:禁止新增元素\n const invalid = violatesIntersection || violatesUnion;\n\n if (invalid) {\n // 取消本次调整:恢复选择与覆盖层\n const union = new Set<Element>();\n groups.forEach((g) => g.forEach((el) => union.add(el)));\n updateDomSelection(union);\n renderGroupOverlays(); // 覆盖层回到原框\n // 结束会话\n resizeSession = null;\n document.removeEventListener(\"mousemove\", onResizeMove);\n notifySelectionEnd();\n return;\n }\n\n groups[idx] = hits;\n // 按所有组并集更新 DOM\n const union = new Set<Element>();\n groups.forEach((g) => g.forEach((el) => union.add(el)));\n updateDomSelection(union);\n // 重绘覆盖层以贴合元素外框\n renderGroupOverlays();\n // 结束会话\n resizeSession = null;\n document.removeEventListener(\"mousemove\", onResizeMove);\n // 通知一次选区结束\n notifySelectionEnd();\n };\n\n // 内部:按下标移除组\n const removeGroupAt = (index: number): boolean => {\n if (index < 0 || index >= groups.length) return false;\n const arr = groups[index];\n if (arr) arr.forEach((el) => ((el as HTMLElement).style.visibility = \"\"));\n groups.splice(index, 1);\n groupHidden.splice(index, 1);\n groupColors.splice(index, 1);\n if (lastCreatedGroupIndex !== null) {\n if (lastCreatedGroupIndex === index) lastCreatedGroupIndex = null;\n else if (lastCreatedGroupIndex > index) lastCreatedGroupIndex--;\n }\n clearGroupOverlays();\n renderGroupOverlays();\n const union = new Set<Element>();\n groups.forEach((g) => g.forEach((el) => union.add(el)));\n updateDomSelection(union);\n // 通知一次选区结束,用于更新结果面板\n notifySelectionEnd();\n return true;\n };\n\n // 内部:将指定元素集合加入为一个新组(遵循交/并限制与去重规则)\n const addGroupInternal = (elements: Element[]): boolean => {\n if (!groupMode) return false;\n if (!Array.isArray(elements) || elements.length === 0) return false;\n // 归一化:去重 + 过滤不在容器内/被排除/不匹配选择器的元素\n const uniq = Array.from(new Set(elements)).filter((el) => {\n try {\n return (\n !!el &&\n container.contains(el) &&\n !isExcluded(el) &&\n (el as Element).matches?.(selectable)\n );\n } catch {\n return false;\n }\n });\n if (uniq.length === 0) return false;\n\n // 阻止重复编组:与现有某组元素集合完全一致\n const dup = findDuplicateGroupIndex(uniq);\n if (dup !== null) return false;\n\n // 与当前选择并集进行“交/并限制”校验\n // 针对“交/并”限制做精细化:允许包含关系(若 allowContainmentSelection=true)\n const hitsSet = new Set<Element>(uniq);\n let partialOverlapFound = false;\n let containmentFound = false;\n for (const g of groups) {\n const gSet = new Set<Element>(g);\n let interCount = 0;\n for (const el of hitsSet) if (gSet.has(el)) interCount++;\n if (interCount === 0) continue;\n if (interCount === gSet.size && interCount === hitsSet.size) {\n // equal -> 视为重复(已在上方重复检测处理),这里忽略\n continue;\n } else if (interCount === gSet.size || interCount === hitsSet.size) {\n containmentFound = true;\n } else {\n partialOverlapFound = true;\n break;\n }\n }\n const base = new Set<Element>(selectedSet); // 当前整体选中(用于并集限制)\n const violatesIntersection = !allowIntersectionSelection && (\n partialOverlapFound ||\n (!allowContainmentSelection && containmentFound)\n );\n const violatesUnion =\n !allowUnionSelection && base.size > 0 && uniq.length > 0;\n if (violatesIntersection || violatesUnion) return false;\n\n // 正式创建新组\n groups.push(uniq);\n groupHidden.push(false);\n groupColors.push(getNewGroupColor());\n lastCreatedGroupIndex = groups.length - 1;\n // 更新 DOM 选中与覆盖层\n const union = new Set<Element>();\n groups.forEach((g) => g.forEach((el) => union.add(el)));\n updateDomSelection(union);\n renderGroupOverlays();\n notifySelectionEnd();\n return true;\n };\n\n const resolveCombineMode = (\n e: MouseEvent\n ): \"replace\" | \"add\" | \"subtract\" | \"toggle\" => {\n if (groupMode) return \"add\"; // 编组时默认累加\n const fallback = multi ? combineMode ?? \"add\" : \"replace\";\n if (!multi) return \"replace\";\n if (combineMode === \"auto\") {\n if (e.shiftKey) return \"add\";\n if (e.altKey) return \"subtract\";\n if (e.metaKey || e.ctrlKey) return \"toggle\";\n return \"add\";\n }\n return (combineMode as any) ?? fallback;\n };\n\n const updateDomSelection = (next: Set<Element>) => {\n // 移除不再选中的\n for (const el of Array.from(selectedSet)) {\n if (!next.has(el)) (el as Element).classList.remove(selectedClass);\n }\n // 添加新选中的\n for (const el of Array.from(next)) {\n if (!selectedSet.has(el)) (el as Element).classList.add(selectedClass);\n }\n selectedSet = next;\n if (onChange) {\n if (groupMode) {\n onChange({\n type: \"groups\",\n groups: groups.slice(),\n flat: Array.from(selectedSet),\n });\n } else {\n onChange({ type: \"single\", selected: Array.from(selectedSet) });\n }\n }\n };\n\n const combineWith = (\n base: Set<Element>,\n hits: Element[],\n mode: \"replace\" | \"add\" | \"subtract\" | \"toggle\"\n ): Set<Element> => {\n if (mode === \"replace\") return new Set(hits);\n const result = new Set(base);\n if (mode === \"add\") {\n for (const h of hits) result.add(h);\n } else if (mode === \"subtract\") {\n for (const h of hits) result.delete(h);\n } else if (mode === \"toggle\") {\n for (const h of hits) {\n if (result.has(h)) result.delete(h);\n else result.add(h);\n }\n }\n return result;\n };\n\n // 在 document 级别监听,保证拖拽过程中不丢失事件\n const onMouseDown = (e: MouseEvent) => {\n // 仅左键\n if (e.button !== 0) return;\n\n // 限制必须在容器内按下,body可以选\n const target = e.target as Node;\n if (!container.contains(target) && target !== document.body) return;\n\n // 记录起点\n startX = e.clientX;\n startY = e.clientY;\n isDragging = true;\n marqueeEl = createMarquee();\n // 记录多选基线与模式\n dragCombine = resolveCombineMode(e);\n baseSet = new Set(selectedSet);\n e.preventDefault();\n };\n\n const onMouseMove = (e: MouseEvent) => {\n // 悬浮高亮:仅在未拖拽时处理\n if (!isDragging && hoverHighlight) {\n const t = e.target as Element | null;\n const cand = t?.closest?.(selectable) as Element | null;\n if (cand && container.contains(cand) && !isExcluded(cand))\n setHovered(cand);\n else setHovered(null);\n }\n if (!isDragging || !marqueeEl) return;\n const { left, top, width, height } = getCurrentMarqueeRect(\n startX,\n startY,\n e.clientX,\n e.clientY\n );\n marqueeEl.style.left = `${left}px`;\n marqueeEl.style.top = `${top}px`;\n marqueeEl.style.width = `${width}px`;\n marqueeEl.style.height = `${height}px`;\n // 实时高亮(预览合并后的集合)\n const hits = computeSelection(left, top, width, height);\n const base = baseSet ?? new Set<Element>();\n // 规则校验\n const hitsSet = new Set<Element>(hits);\n let interCount = 0;\n for (const el of hitsSet) if (base.has(el)) interCount++;\n let relation: 'disjoint'|'equal'|'containment'|'partial' = 'disjoint';\n if (interCount === 0) relation = 'disjoint';\n else if (interCount === hitsSet.size && interCount === base.size) relation = 'equal';\n else if (interCount === hitsSet.size || interCount === base.size) relation = 'containment';\n else relation = 'partial';\n const violatesIntersection = !allowIntersectionSelection && (\n relation === 'partial' || (!allowContainmentSelection && relation === 'containment')\n );\n const violatesUnion =\n !allowUnionSelection && base.size > 0 && hits.length > 0;\n dragInvalid = violatesIntersection || violatesUnion;\n // 提示红框/蓝框\n if (marqueeEl) {\n if (dragInvalid) {\n marqueeEl.style.outline = \"1px dashed #ff4d4f\";\n marqueeEl.style.background = \"rgba(255,77,79,0.12)\";\n } else {\n marqueeEl.style.outline = \"1px dashed #268aff\";\n marqueeEl.style.background = \"rgba(38,138,255,0.12)\";\n }\n }\n // 预览:无效则保持基线不变,有效才合并预览\n if (dragInvalid) {\n updateDomSelection(base);\n } else {\n const next = combineWith(base, hits, dragCombine);\n updateDomSelection(next);\n }\n };\n\n const onMouseUp = (e: MouseEvent) => {\n if (!isDragging) return;\n isDragging = false;\n if (marqueeEl && marqueeEl.parentNode)\n marqueeEl.parentNode.removeChild(marqueeEl);\n marqueeEl = null;\n\n // 最终一次计算,确保结果准确\n const { left, top, width, height } = getCurrentMarqueeRect(\n startX,\n startY,\n e.clientX,\n e.clientY\n );\n const hits = computeSelection(left, top, width, height);\n const base = baseSet ?? new Set<Element>();\n // 规则校验(与 move 同步)\n const hitsSet = new Set<Element>(hits);\n let interCount = 0;\n for (const el of hitsSet) if (base.has(el)) interCount++;\n let relation: 'disjoint'|'equal'|'containment'|'partial' = 'disjoint';\n if (interCount === 0) relation = 'disjoint';\n else if (interCount === hitsSet.size && interCount === base.size) relation = 'equal';\n else if (interCount === hitsSet.size || interCount === base.size) relation = 'containment';\n else relation = 'partial';\n const violatesIntersection = !allowIntersectionSelection && (\n relation === 'partial' || (!allowContainmentSelection && relation === 'containment')\n );\n const violatesUnion =\n !allowUnionSelection && base.size > 0 && hits.length > 0;\n const invalid = violatesIntersection || violatesUnion;\n if (invalid) {\n // 直接取消本次圈选\n updateDomSelection(base);\n baseSet = null;\n notifySelectionEnd();\n return;\n }\n const next = combineWith(base, hits, dragCombine);\n updateDomSelection(next);\n if (groupMode && hits.length > 0) {\n // 阻止重复编组:与现有某组元素集合完全一致\n const dup = findDuplicateGroupIndex(hits);\n if (dup !== null) {\n try {\n console.warn(`重复编组被阻止:与已存在的第${dup + 1}组元素完全一致`);\n } catch {}\n // 仍然完成一次交互通知(但不创建新组)\n baseSet = null;\n notifySelectionEnd();\n return;\n }\n groups.push(hits);\n lastCreatedGroupIndex = groups.length - 1;\n groupHidden.push(false);\n groupColors.push(getNewGroupColor());\n const union = new Set<Element>();\n groups.forEach((g) => g.forEach((el) => union.add(el)));\n updateDomSelection(union);\n renderGroupOverlays();\n }\n baseSet = null;\n // 通知监听者:一次完整拖拽已结束\n notifySelectionEnd();\n };\n\n // 双击快速成组(以双击元素的外框作为选择框)\n const onDblClick = (e: MouseEvent) => {\n if (!quickGroupOnDblClick || !groupMode) return;\n const target = e.target as Element | null;\n if (!target) return;\n // 限制在容器内\n let node: Element | null = target as Element;\n if (quickGroupSelector) {\n node = (target.closest?.(quickGroupSelector) as Element) || null;\n }\n if (!node || !container.contains(node)) return;\n const r = node.getBoundingClientRect();\n const hits = computeSelection(r.left, r.top, r.width, r.height);\n // 与当前选择的冲突检测\n const base = new Set<Element>(selectedSet);\n const hitsSet = new Set<Element>(hits);\n let interCount = 0;\n for (const el of hitsSet) if (base.has(el)) interCount++;\n let relation: 'disjoint'|'equal'|'containment'|'partial' = 'disjoint';\n if (interCount === 0) relation = 'disjoint';\n else if (interCount === hitsSet.size && interCount === base.size) relation = 'equal';\n else if (interCount === hitsSet.size || interCount === base.size) relation = 'containment';\n else relation = 'partial';\n const violatesIntersection = !allowIntersectionSelection && (\n relation === 'partial' || (!allowContainmentSelection && relation === 'containment')\n );\n const violatesUnion =\n !allowUnionSelection && base.size > 0 && hits.length > 0;\n if (hits.length === 0 || violatesIntersection || violatesUnion) {\n // 无命中也触发一次刷新,确保面板与状态同步(可选择忽略)\n notifySelectionEnd();\n return;\n }\n // 阻止重复编组:与现有某组元素集合完全一致\n const dup = findDuplicateGroupIndex(hits);\n if (dup !== null) {\n try {\n console.warn(`重复编组被阻止:与已存在的第${dup + 1}组元素完全一致`);\n } catch {}\n notifySelectionEnd();\n return;\n }\n groups.push(hits);\n lastCreatedGroupIndex = groups.length - 1;\n groupHidden.push(false);\n groupColors.push(getNewGroupColor());\n const union = new Set<Element>();\n groups.forEach((g) => g.forEach((el) => union.add(el)));\n updateDomSelection(union);\n renderGroupOverlays();\n notifySelectionEnd();\n };\n\n // 容器离开时清除悬浮样式\n const onContainerLeave = () => setHovered(null);\n\n function computeSelection(\n left: number,\n top: number,\n width: number,\n height: number\n ): Element[] {\n // 空框直接返回空\n if (width === 0 || height === 0) return [];\n\n // 限制只计算容器可见区域内元素\n const containerRect = container.getBoundingClientRect();\n const marqueeRect = new DOMRect(left, top, width, height);\n\n // 仅在与容器区域相交时才继续\n if (!rectIntersects(marqueeRect, containerRect)) return [];\n\n const nodes = Array.from(container.querySelectorAll(selectable));\n let selected: Element[] = [];\n const scoreMap = new Map<Element, number>();\n for (const el of nodes) {\n // 跳过排除元素\n if (isExcluded(el)) continue;\n const r = el.getBoundingClientRect();\n // 可选策略:先与容器相交,再与选择框判断\n if (!rectIntersects(r, containerRect)) continue;\n\n let hit = false;\n if (selectionMode === \"contains\") {\n hit = rectContains(marqueeRect, r);\n } else if (selectionMode === \"center\") {\n const cx = r.left + r.width / 2;\n const cy = r.top + r.height / 2;\n hit =\n cx >= marqueeRect.left &&\n cx <= marqueeRect.right &&\n cy >= marqueeRect.top &&\n cy <= marqueeRect.bottom;\n } else {\n // intersects + 面积占比阈值\n if (rectIntersects(marqueeRect, r)) {\n const ratio = getRatio(marqueeRect, r);\n hit = ratio >= Math.max(0, Math.min(1, minOverlapRatio));\n }\n }\n if (hit) {\n const score =\n selectionMode === \"contains\" ? 1 : getRatio(marqueeRect, r);\n scoreMap.set(el, score);\n selected.push(el);\n }\n }\n\n // 冲突处理\n const strategy: \"none\" | \"leaf\" | \"best\" =\n conflictStrategy ?? (preventAncestorSelection ? \"leaf\" : \"none\");\n if (strategy !== \"none\" && selected.length > 1) {\n if (strategy === \"leaf\") {\n // 仅保留叶子命中的元素,避免选中大容器\n selected = selected.filter(\n (el) =>\n !selected.some(\n (other) => other !== el && (el as Node).contains(other)\n )\n );\n } else if (strategy === \"best\") {\n // 在每条祖先链上保留分数更高者\n const byScoreDesc = [...selected].sort(\n (a, b) => (scoreMap.get(b) || 0) - (scoreMap.get(a) || 0)\n );\n const kept: Element[] = [];\n for (const el of byScoreDesc) {\n const conflict = kept.find(\n (k) => (k as Node).contains(el) || (el as Node).contains(k)\n );\n if (!conflict) kept.push(el);\n }\n selected = kept;\n }\n }\n\n return selected;\n }\n\n // 绑定监听\n document.addEventListener(\"mousedown\", onMouseDown, true);\n document.addEventListener(\"mousemove\", onMouseMove);\n document.addEventListener(\"mouseup\", onMouseUp);\n if (hoverHighlight) {\n container.addEventListener(\"mouseleave\", onContainerLeave);\n }\n if (groupMode && quickGroupOnDblClick) {\n container.addEventListener(\"dblclick\", onDblClick);\n }\n // 监听滚动与尺寸变化,刷新组外框位置\n const onScrollOrResize = () => renderGroupOverlays();\n if (groupMode) {\n window.addEventListener(\"scroll\", onScrollOrResize, true);\n window.addEventListener(\"resize\", onScrollOrResize);\n }\n\n // 返回销毁器\n const buildSnapshot = (): MarqueeSelectionSnapshot => {\n if (groupMode) {\n const rects = groups.map((g) => calcGroupRect(g));\n // 计算组级嵌套:根据外接矩形包含关系,找到每个组的最近父组\n const parents: (number | null)[] = Array(groups.length).fill(null);\n const areas = rects.map((r) =>\n r ? Math.max(0, r.width * r.height) : Number.POSITIVE_INFINITY\n );\n for (let i = 0; i < groups.length; i++) {\n const ri = rects[i];\n if (!ri) continue;\n let best: number | null = null;\n let bestArea = Number.POSITIVE_INFINITY;\n for (let j = 0; j < groups.length; j++) {\n if (i === j) continue;\n const rj = rects[j];\n if (!rj) continue;\n const contains =\n rj.left <= ri.left &&\n rj.top <= ri.top &&\n rj.left + rj.width >= ri.left + ri.width &&\n rj.top + rj.height >= ri.top + ri.height;\n if (contains) {\n const area = Number(areas[j]);\n if (area < bestArea) {\n bestArea = area;\n best = j;\n }\n }\n }\n parents[i] = best;\n }\n const children: number[][] = Array.from(\n { length: groups.length },\n () => []\n );\n for (let i = 0; i < groups.length; i++) {\n const p = parents[i];\n if (p !== null && p !== undefined && children[p]) children[p].push(i);\n }\n const roots: number[] = [];\n for (let i = 0; i < groups.length; i++) {\n if (parents[i] === null || parents[i] === undefined) roots.push(i);\n }\n return {\n type: \"groups\",\n groups: groups.map((g) => g.slice()),\n flat: Array.from(selectedSet),\n hidden: groupHidden.slice(),\n groupRects: rects,\n groupNesting: { parents, children, roots },\n };\n }\n return { type: \"single\", selected: Array.from(selectedSet) };\n };\n\n const notifySelectionEnd = () => {\n const snap = buildSnapshot();\n // 先调用可选的 options 回调\n if (onSelectionEndOption) {\n try {\n onSelectionEndOption(snap);\n } catch {}\n }\n for (const fn of endListeners) {\n try {\n fn(snap);\n } catch {}\n }\n const waiters = endWaiters.splice(0);\n for (const resolve of waiters) {\n try {\n resolve(snap);\n } catch {}\n }\n };\n\n const controller: MarqueeSelectionController = {\n destroy() {\n document.removeEventListener(\"mousedown\", onMouseDown);\n document.removeEventListener(\"mousemove\", onMouseMove);\n document.removeEventListener(\"mouseup\", onMouseUp);\n // 清理选择框与样式\n if (marqueeEl && marqueeEl.parentNode)\n marqueeEl.parentNode.removeChild(marqueeEl);\n marqueeEl = null;\n const prev = container.querySelectorAll(`.${selectedClass}`);\n prev.forEach((n) => n.classList.remove(selectedClass));\n if (hoverHighlight) {\n container.removeEventListener(\"mouseleave\", onContainerLeave);\n setHovered(null);\n }\n if (groupMode) {\n window.removeEventListener(\"scroll\", onScrollOrResize, true);\n window.removeEventListener(\"resize\", onScrollOrResize);\n }\n if (groupMode && quickGroupOnDblClick) {\n container.removeEventListener(\"dblclick\", onDblClick);\n }\n clearGroupOverlays();\n // 恢复所有元素可见\n groups.forEach((g) =>\n g.forEach((el) => ((el as HTMLElement).style.visibility = \"\"))\n );\n groups = [];\n groupHidden = [];\n groupColors = [];\n lastCreatedGroupIndex = null;\n selectedSet.clear();\n endListeners.splice(0);\n endWaiters.splice(0);\n },\n getGroups() {\n return groups.slice();\n },\n clearGroups() {\n // 恢复所有元素可见\n groups.forEach((g) =>\n g.forEach((el) => ((el as HTMLElement).style.visibility = \"\"))\n );\n groups = [];\n groupHidden = [];\n groupColors = [];\n lastCreatedGroupIndex = null;\n clearGroupOverlays();\n const empty = new Set<Element>();\n updateDomSelection(empty);\n },\n removeGroup(index: number) {\n return removeGroupAt(index);\n },\n addGroup(elements: Element[]) {\n return addGroupInternal(elements);\n },\n setGroupVisibility(index: number, hidden: boolean) {\n return setGroupHidden(index, hidden);\n },\n toggleGroupVisibility(index: number) {\n if (index < 0 || index >= groups.length) return false;\n groupHidden[index] = !groupHidden[index];\n applyGroupVisibility(index);\n renderGroupOverlays();\n return true;\n },\n getSelectionResult() {\n return buildSnapshot();\n },\n refresh() {\n renderGroupOverlays();\n },\n hideOverlays() {\n clearGroupOverlays();\n },\n showAndRefreshOverlays() {\n renderGroupOverlays();\n },\n // 获取当前组级嵌套信息\n getGroupNesting() {\n const snap = buildSnapshot();\n return snap.type === \"groups\" ? snap.groupNesting : null;\n },\n onSelectionEnd(handler: (snapshot: MarqueeSelectionSnapshot) => void) {\n endListeners.push(handler);\n return () => {\n const i = endListeners.indexOf(handler);\n if (i >= 0) endListeners.splice(i, 1);\n };\n },\n waitForSelectionEnd() {\n return new Promise<MarqueeSelectionSnapshot>((resolve) => {\n endWaiters.push(resolve);\n });\n },\n };\n controllerRef = controller;\n return controller;\n}\n\nexport default marqueeSelection;\n"],"names":["marqueeSelection","options","container","selectable","exclude","selectionMode","minOverlapRatio","overlapMetric","selectedClass","onChange","preventAncestorSelection","conflictStrategy","groupMode","groupOverlayClass","groupColor","groupRandomColor","groupColorPalette","multi","combineMode","hoverHighlight","hoverClass","onSelectionEndOption","quickGroupOnDblClick","quickGroupSelector","allowIntersectionSelection","allowUnionSelection","allowContainmentSelection","toolbarButtons","excludeSelectors","isExcluded","el","sel","startX","startY","isDragging","marqueeEl","dragInvalid","selectedSet","baseSet","dragCombine","groups","groupOverlays","groupHidden","groupColors","pickPastel","getNewGroupColor","idx","lastCreatedGroupIndex","endListeners","endWaiters","resizeSession","findDuplicateGroupIndex","els","target","i","g","same","gs","controllerRef","applyGroupVisibility","index","hidden","setGroupHidden","hoveredEl","setHovered","createMarquee","rectIntersects","a","b","rectContains","outer","inner","overlapRatio","left","right","top","bottom","w","h","overlap","areaB","iouRatio","inter","areaA","union","getRatio","marqueeRect","elementRect","getCurrentMarqueeRect","x1","y1","x2","y2","width","height","calcGroupRect","rects","r","clearGroupOverlays","renderGroupOverlays","placedToolbarRects","rectsOverlap","box","color","toolbar","label","toggleBtn","ev","notifySelectionEnd","removeBtn","removeGroupAt","getIntersectingIndices","selfIdx","selfRect","list","og","j","ob","orect","ints","mergeBtn","openPanel","old","panel","title","listWrap","checkboxRefs","row","cb","txt","actions","ok","cancel","chosen","c","n","ci","sorted","newIdx","ri","unionSel","updateDomSelection","addCustomButton","cfg","btn","_a","buildSnapshot","anchors","prevVisibility","step","margin","k","rect","collide","pr","ov","addHandle","side","thickness","onResizeMove","onResizeEnd","e","startRect","overlay","dx","dy","minSize","hits","computeSelection","currentSet","otherSet","hitsSet","partialOverlapFound","containmentFound","gSet","interCount","deltaAddCount","violatesIntersection","violatesUnion","arr","addGroupInternal","elements","uniq","base","resolveCombineMode","fallback","next","combineWith","mode","result","onMouseDown","onMouseMove","t","cand","relation","onMouseUp","dup","onDblClick","node","onContainerLeave","containerRect","nodes","selected","scoreMap","hit","cx","cy","score","strategy","other","byScoreDesc","kept","onScrollOrResize","parents","areas","best","bestArea","rj","area","children","p","roots","snap","fn","waiters","resolve","controller","handler"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
(function(D,X){typeof exports=="object"&&typeof module<"u"?X(exports):typeof define=="function"&&define.amd?define(["exports"],X):(D=typeof globalThis<"u"?globalThis:D||self,X(D.marqueeSelection={}))})(this,function(D){"use strict";function X(Wt){const{container:O,selectable:ut="img",exclude:tt,selectionMode:pt="intersects",minOverlapRatio:Kt=0,overlapMetric:_t="element",selectedClass:et="selected",onChange:dt,preventAncestorSelection:Jt=!0,conflictStrategy:Qt,groupMode:B=!1,groupOverlayClass:Rt,groupColor:ht,groupRandomColor:Zt=!1,groupColorPalette:nt,multi:It=!1,combineMode:yt,hoverHighlight:ot=!1,hoverClass:At="hovered",onSelectionEnd:Lt,quickGroupOnDblClick:gt=!1,quickGroupSelector:Nt,allowIntersectionSelection:j=!0,allowUnionSelection:H=!0,allowContainmentSelection:U=!0,toolbarButtons:mt}=Wt,Ot=Array.isArray(tt)?tt.filter(Boolean):tt?[tt]:[],bt=t=>{if(!t||!Ot.length)return!1;for(const e of Ot)try{if(t instanceof Element&&t.matches(e))return!0}catch{}return!1};if(!O)throw new Error("container is required");let vt=0,xt=0,W=!1,z=null,wt=!1,F=new Set,V=null,Et="replace",a=[],st=[],I=[],Y=[];const te=()=>`hsl(${Math.floor(Math.random()*360)}, 70%, 55%)`,St=()=>{if(ht&&typeof ht=="string")return ht;if(Zt){if(Array.isArray(nt)&&nt.length>0){const t=Math.floor(Math.random()*nt.length);return nt[t]}return te()}return"rgba(255, 165, 0, 0.9)"};let k=null;const K=[],Ct=[];let T=null;const zt=t=>{if(!t.length)return null;const e=new Set(t);for(let r=0;r<a.length;r++){const i=a[r]||[];if(i.length!==e.size)continue;let c=!0;const o=new Set(i);if(o.size!==e.size&&(c=!1),c){for(const n of e)if(!o.has(n)){c=!1;break}}if(c)return r}return null};let Gt=null;const Bt=t=>{const e=!!I[t],r=a[t]||[];for(const i of r)i.style.visibility=e?"hidden":""},lt=(t,e)=>t<0||t>=a.length?!1:(I[t]=e,Bt(t),!0);let _=null;const rt=t=>{ot&&(_&&_!==t&&_.classList.remove(At),t&&_!==t&&t.classList.add(At),_=t)},ee=()=>{const t=document.createElement("div");return t.style.position="fixed",t.style.left="0px",t.style.top="0px",t.style.width="0px",t.style.height="0px",t.style.outline="1px dashed #268aff",t.style.background="rgba(38,138,255,0.12)",t.style.pointerEvents="none",t.style.zIndex="2147483647",t.style.boxSizing="border-box",document.body.appendChild(t),t},it=(t,e)=>t.left<e.right&&t.right>e.left&&t.top<e.bottom&&t.bottom>e.top,ne=(t,e)=>t.left<=e.left&&t.right>=e.right&&t.top<=e.top&&t.bottom>=e.bottom,oe=(t,e)=>{const r=Math.max(t.left,e.left),i=Math.min(t.right,e.right),c=Math.max(t.top,e.top),o=Math.min(t.bottom,e.bottom),n=Math.max(0,i-r),s=Math.max(0,o-c),y=n*s,d=Math.max(1,e.width*e.height);return y/d},se=(t,e)=>{const r=Math.max(t.left,e.left),i=Math.min(t.right,e.right),c=Math.max(t.top,e.top),o=Math.min(t.bottom,e.bottom),n=Math.max(0,i-r),s=Math.max(0,o-c),y=n*s,d=Math.max(1,t.width*t.height),u=Math.max(1,e.width*e.height),h=d+u-y;return y/h},Ft=(t,e)=>_t==="iou"?se(t,e):oe(t,e),qt=(t,e,r,i)=>{const c=Math.min(t,r),o=Math.min(e,i),n=Math.abs(r-t),s=Math.abs(i-e);return{left:c,top:o,width:n,height:s}},Mt=t=>{const e=t.map(n=>n.getBoundingClientRect()).filter(n=>n.width>0&&n.height>0);if(!e.length)return null;const r=Math.min(...e.map(n=>n.left)),i=Math.min(...e.map(n=>n.top)),c=Math.max(...e.map(n=>n.right)),o=Math.max(...e.map(n=>n.bottom));return{left:r,top:i,width:c-r,height:o-i}},J=()=>{st.forEach(t=>t.remove()),st=[]},L=()=>{if(J(),!B)return;const t=[],e=(r,i)=>r.left<i.right&&r.right>i.left&&r.top<i.bottom&&r.bottom>i.top;a.forEach((r,i)=>{const c=Mt(r);if(!c)return;const o=Y[i]||"rgba(255, 165, 0, 0.9)",n=document.createElement("div");n.style.position="fixed",n.style.pointerEvents="none",n.style.zIndex="2147483646",n.style.left=`${c.left}px`,n.style.top=`${c.top}px`,n.style.width=`${c.width}px`,n.style.height=`${c.height}px`,n.style.boxSizing="border-box",n.style.outline=`1px solid ${o}`,n.style.background="transparent",document.body.appendChild(n);const s=document.createElement("div");s.style.position="absolute",s.style.display="inline-flex",s.style.alignItems="center",s.style.gap="6px",s.style.minWidth="max-content",s.style.padding="2px 6px",s.style.fontSize="12px",s.style.lineHeight="16px",s.style.color="#fff",s.style.background=o,s.style.borderRadius="4px",s.style.pointerEvents="auto";const y=document.createElement("span");y.textContent=`组 ${i+1}`;const d=document.createElement("button");d.textContent=I[i]?"显示":"隐藏",d.style.background="rgba(0,0,0,0.15)",d.style.border="none",d.style.color="#fff",d.style.padding="2px 6px",d.style.borderRadius="3px",d.style.cursor="pointer",d.onclick=b=>{b.stopPropagation(),lt(i,!I[i]),L(),N()};const u=document.createElement("button");u.textContent="取消组",u.style.background="rgba(0,0,0,0.15)",u.style.border="none",u.style.color="#fff",u.style.padding="2px 6px",u.style.borderRadius="3px",u.style.cursor="pointer",u.onclick=b=>{b.stopPropagation(),lt(i,!1),Pt(i)},s.appendChild(y),s.appendChild(d),s.appendChild(u);const h=b=>{const l=c?new DOMRect(c.left,c.top,c.width,c.height):null;if(!l)return[];const f=[];return a.forEach((w,p)=>{if(p===b)return;const x=Mt(w);if(!x)return;const S=new DOMRect(x.left,x.top,x.width,x.height);it(l,S)&&f.push(p)}),f};if((()=>{if(k!==i)return;const b=h(i);if(b.length===0)return;const l=document.createElement("button");l.textContent="合并",l.style.background="rgba(0,0,0,0.15)",l.style.border="none",l.style.color="#fff",l.style.padding="2px 6px",l.style.borderRadius="3px",l.style.cursor="pointer";const f=()=>{const w=s.querySelector(".merge-panel");w&&w.remove();const p=document.createElement("div");p.className="merge-panel",p.style.position="absolute",p.style.left="0",p.style.top="22px",p.style.minWidth="160px",p.style.padding="8px",p.style.background="#fff",p.style.color="#333",p.style.border="1px solid rgba(0,0,0,0.15)",p.style.borderRadius="6px",p.style.boxShadow="0 4px 12px rgba(0,0,0,0.15)",p.style.pointerEvents="auto",p.style.zIndex="2147483647";const x=document.createElement("div");x.textContent="选择要合并的组",x.style.fontSize="12px",x.style.marginBottom="6px",p.appendChild(x);const S=document.createElement("div");S.style.maxHeight="200px",S.style.overflow="auto";const q=[];b.forEach(M=>{const R=document.createElement("label");R.style.display="flex",R.style.alignItems="center",R.style.gap="6px",R.style.fontSize="12px",R.style.margin="4px 0";const G=document.createElement("input");G.type="checkbox",G.checked=!0,G.value=String(M);const Z=document.createElement("span");Z.textContent=`组 ${M+1}`,R.appendChild(G),R.appendChild(Z),S.appendChild(R),q.push(G)}),p.appendChild(S);const P=document.createElement("div");P.style.display="flex",P.style.gap="8px",P.style.marginTop="8px";const C=document.createElement("button");C.textContent="确认",C.style.padding="2px 8px",C.style.cursor="pointer";const $=document.createElement("button");$.textContent="取消",$.style.padding="2px 8px",$.style.cursor="pointer",P.appendChild(C),P.appendChild($),p.appendChild(P),$.onclick=M=>{M.stopPropagation(),p.remove()},C.onclick=M=>{M.stopPropagation();const R=q.filter(E=>E.checked).map(E=>parseInt(E.value,10)).filter(E=>!Number.isNaN(E));if(R.length===0){p.remove();return}const G=new Set;(a[i]||[]).forEach(E=>G.add(E)),R.forEach(E=>{(a[E]||[]).forEach(ae=>G.add(ae))}),a[i]=Array.from(G);const ce=[...R].sort((E,ft)=>ft-E);let kt=i;ce.forEach(E=>{E<0||E>=a.length||E===i||(lt(E,!1),a.splice(E,1),I.splice(E,1),Y.splice(E,1),k!==null&&(k===E?k=null:k>E&&k--),E<kt&&kt--)}),k=kt;const Vt=new Set;a.forEach(E=>E.forEach(ft=>Vt.add(ft))),A(Vt),L(),p.remove(),N()},s.appendChild(p)};l.onclick=w=>{w.stopPropagation(),f()},s.appendChild(l)})(),n.appendChild(s),mt&&mt.length){const b=l=>{const f=document.createElement("button");f.textContent=l.label||"按钮",f.title=l.title||"",f.style.background="rgba(0,0,0,0.15)",f.style.border="none",f.style.color="#fff",f.style.padding="2px 6px",f.style.borderRadius="3px",f.style.cursor="pointer",l.className&&(f.className+=(f.className?" ":"")+l.className),f.onclick=w=>{var p;w.stopPropagation();try{(p=l.onClick)==null||p.call(l,{index:i,group:a[i]||[],controller:Gt,getSnapshot:()=>at(),refresh:()=>{L(),N()},mouseX:w.clientX,mouseY:w.clientY,anchorRect:s.getBoundingClientRect(),anchorEl:s,overlayEl:n})}catch{}},s.appendChild(f)};mt.forEach(b)}(()=>{const b=["tl","tr","bl","br"],l=s.style.visibility;s.style.visibility="hidden";const f=28,w=6;t:for(let p=0;p<b.length;p++)for(let x=0;x<6;x++){s.style.left="",s.style.right="",s.style.top="",s.style.bottom="";const S=s.offsetHeight||22;b[p]==="tl"?(s.style.left="0",s.style.top=`${-S-w+x*f}px`):b[p]==="tr"?(s.style.right="0",s.style.top=`${-S-w+x*f}px`):b[p]==="bl"?(s.style.left="0",s.style.top=`${c.height+w+x*f}px`):(s.style.right="0",s.style.top=`${c.height+w+x*f}px`);const q=s.getBoundingClientRect(),P={left:q.left,top:q.top,right:q.right,bottom:q.bottom};let C=!1;for(const $ of t)if(e(P,$)){C=!0;break}if(!C){t.push(P);break t}}s.style.visibility=l})(),s.addEventListener("mouseenter",()=>{try{st.forEach(b=>b.style.zIndex="2147483646"),n.style.zIndex="2147483647"}catch{}});const v=b=>{const l=document.createElement("div");l.style.position="absolute",l.style.pointerEvents="auto",l.style.background="transparent",l.style.zIndex="2147483647";const f=8;b==="top"?(l.style.cursor="ns-resize",l.style.left="-4px",l.style.right="-4px",l.style.top=`-${f/2|0}px`,l.style.height=`${f}px`):b==="bottom"?(l.style.cursor="ns-resize",l.style.left="-4px",l.style.right="-4px",l.style.bottom=`-${f/2|0}px`,l.style.height=`${f}px`):b==="left"?(l.style.cursor="ew-resize",l.style.top="-4px",l.style.bottom="-4px",l.style.left=`-${f/2|0}px`,l.style.width=`${f}px`):b==="right"?(l.style.cursor="ew-resize",l.style.top="-4px",l.style.bottom="-4px",l.style.right=`-${f/2|0}px`,l.style.width=`${f}px`):b==="nw"?(l.style.cursor="nwse-resize",l.style.left=`-${f/2|0}px`,l.style.top=`-${f/2|0}px`,l.style.width=`${f}px`,l.style.height=`${f}px`):b==="ne"?(l.style.cursor="nesw-resize",l.style.right=`-${f/2|0}px`,l.style.top=`-${f/2|0}px`,l.style.width=`${f}px`,l.style.height=`${f}px`):b==="sw"?(l.style.cursor="nesw-resize",l.style.left=`-${f/2|0}px`,l.style.bottom=`-${f/2|0}px`,l.style.width=`${f}px`,l.style.height=`${f}px`):b==="se"&&(l.style.cursor="nwse-resize",l.style.right=`-${f/2|0}px`,l.style.bottom=`-${f/2|0}px`,l.style.width=`${f}px`,l.style.height=`${f}px`),l.onmousedown=w=>{w.preventDefault(),w.stopPropagation();const p={left:parseFloat(n.style.left||"0"),top:parseFloat(n.style.top||"0"),width:parseFloat(n.style.width||"0"),height:parseFloat(n.style.height||"0")};T={idx:i,side:b,startX:w.clientX,startY:w.clientY,startRect:p,overlay:n},document.addEventListener("mousemove",$t),document.addEventListener("mouseup",le,{once:!0})},n.appendChild(l)};v("top"),v("right"),v("bottom"),v("left"),v("nw"),v("ne"),v("sw"),v("se"),Rt&&n.classList.add(Rt),st.push(n)})},$t=t=>{if(!T)return;const{idx:e,side:r,startX:i,startY:c,startRect:o,overlay:n}=T,s=t.clientX-i,y=t.clientY-c;let d=o.left,u=o.top,h=o.width,g=o.height;const m=4;r==="left"||r==="nw"||r==="sw"?(d=o.left+s,h=o.width-s,h<m&&(d=o.left+(o.width-m),h=m)):(r==="right"||r==="ne"||r==="se")&&(h=o.width+s,h<m&&(h=m)),r==="top"||r==="nw"||r==="ne"?(u=o.top+y,g=o.height-y,g<m&&(u=o.top+(o.height-m),g=m)):(r==="bottom"||r==="sw"||r==="se")&&(g=o.height+y,g<m&&(g=m)),n.style.left=`${d}px`,n.style.top=`${u}px`,n.style.width=`${h}px`,n.style.height=`${g}px`;const v=Q(d,u,h,g),b=new Set(a[e]||[]),l=new Set;a.forEach((C,$)=>{$!==e&&C.forEach(M=>l.add(M))});const f=new Set(v);let w=!1,p=!1;for(let C=0;C<a.length;C++){if(C===e)continue;const $=new Set(a[C]||[]);let M=0;for(const R of f)$.has(R)&&M++;if(M!==0&&!(M===$.size&&M===f.size))if(M===$.size)p=!0;else if(M===f.size)p=!0;else{w=!0;break}}const x=v.filter(C=>!b.has(C)).length,S=!j&&(w||!U&&p),q=!H&&x>0;if(S||q){n.style.outline="1px dashed #ff4d4f",n.style.background="rgba(255,77,79,0.06)";const C=new Set;a.forEach(($,M)=>{(M===e?a[e]||[]:$).forEach(G=>C.add(G))}),A(C)}else{const C=Y[e]||"rgba(255, 165, 0, 0.9)";n.style.outline=`1px solid ${C}`,n.style.background="transparent";const $=new Set;a.forEach((M,R)=>{(R===e?v:M).forEach(Z=>$.add(Z))}),A($)}},le=t=>{if(!T)return;const{idx:e,overlay:r,startRect:i}=T,c=parseFloat(r.style.left||"0"),o=parseFloat(r.style.top||"0"),n=parseFloat(r.style.width||"0"),s=parseFloat(r.style.height||"0"),y=Q(c,o,n,s),d=new Set(a[e]||[]),u=new Set;a.forEach((p,x)=>{x!==e&&p.forEach(S=>u.add(S))});const h=new Set(y);let g=!1,m=!1;for(let p=0;p<a.length;p++){if(p===e)continue;const x=new Set(a[p]||[]);let S=0;for(const q of h)x.has(q)&&S++;if(S!==0&&!(S===x.size&&S===h.size))if(S===x.size||S===h.size)m=!0;else{g=!0;break}}const v=y.filter(p=>!d.has(p)).length,b=!j&&(g||!U&&m),l=!H&&v>0;if(b||l){const p=new Set;a.forEach(x=>x.forEach(S=>p.add(S))),A(p),L(),T=null,document.removeEventListener("mousemove",$t),N();return}a[e]=y;const w=new Set;a.forEach(p=>p.forEach(x=>w.add(x))),A(w),L(),T=null,document.removeEventListener("mousemove",$t),N()},Pt=t=>{if(t<0||t>=a.length)return!1;const e=a[t];e&&e.forEach(i=>i.style.visibility=""),a.splice(t,1),I.splice(t,1),Y.splice(t,1),k!==null&&(k===t?k=null:k>t&&k--),J(),L();const r=new Set;return a.forEach(i=>i.forEach(c=>r.add(c))),A(r),N(),!0},re=t=>{if(!B||!Array.isArray(t)||t.length===0)return!1;const e=Array.from(new Set(t)).filter(u=>{var h;try{return!!u&&O.contains(u)&&!bt(u)&&((h=u.matches)==null?void 0:h.call(u,ut))}catch{return!1}});if(e.length===0||zt(e)!==null)return!1;const i=new Set(e);let c=!1,o=!1;for(const u of a){const h=new Set(u);let g=0;for(const m of i)h.has(m)&&g++;if(g!==0&&!(g===h.size&&g===i.size))if(g===h.size||g===i.size)o=!0;else{c=!0;break}}const n=new Set(F),s=!j&&(c||!U&&o),y=!H&&n.size>0&&e.length>0;if(s||y)return!1;a.push(e),I.push(!1),Y.push(St()),k=a.length-1;const d=new Set;return a.forEach(u=>u.forEach(h=>d.add(h))),A(d),L(),N(),!0},ie=t=>{if(B)return"add";const e=It?yt??"add":"replace";return It?yt==="auto"?t.shiftKey?"add":t.altKey?"subtract":t.metaKey||t.ctrlKey?"toggle":"add":yt??e:"replace"},A=t=>{for(const e of Array.from(F))t.has(e)||e.classList.remove(et);for(const e of Array.from(t))F.has(e)||e.classList.add(et);F=t,dt&&dt(B?{type:"groups",groups:a.slice(),flat:Array.from(F)}:{type:"single",selected:Array.from(F)})},Yt=(t,e,r)=>{if(r==="replace")return new Set(e);const i=new Set(t);if(r==="add")for(const c of e)i.add(c);else if(r==="subtract")for(const c of e)i.delete(c);else if(r==="toggle")for(const c of e)i.has(c)?i.delete(c):i.add(c);return i},Dt=t=>{if(t.button!==0)return;const e=t.target;!O.contains(e)&&e!==document.body||(vt=t.clientX,xt=t.clientY,W=!0,z=ee(),Et=ie(t),V=new Set(F),t.preventDefault())},Tt=t=>{var g;if(!W&&ot){const m=t.target,v=(g=m==null?void 0:m.closest)==null?void 0:g.call(m,ut);v&&O.contains(v)&&!bt(v)?rt(v):rt(null)}if(!W||!z)return;const{left:e,top:r,width:i,height:c}=qt(vt,xt,t.clientX,t.clientY);z.style.left=`${e}px`,z.style.top=`${r}px`,z.style.width=`${i}px`,z.style.height=`${c}px`;const o=Q(e,r,i,c),n=V??new Set,s=new Set(o);let y=0;for(const m of s)n.has(m)&&y++;let d="disjoint";y===0?d="disjoint":y===s.size&&y===n.size?d="equal":y===s.size||y===n.size?d="containment":d="partial";const u=!j&&(d==="partial"||!U&&d==="containment"),h=!H&&n.size>0&&o.length>0;if(wt=u||h,z&&(wt?(z.style.outline="1px dashed #ff4d4f",z.style.background="rgba(255,77,79,0.12)"):(z.style.outline="1px dashed #268aff",z.style.background="rgba(38,138,255,0.12)")),wt)A(n);else{const m=Yt(n,o,Et);A(m)}},Xt=t=>{if(!W)return;W=!1,z&&z.parentNode&&z.parentNode.removeChild(z),z=null;const{left:e,top:r,width:i,height:c}=qt(vt,xt,t.clientX,t.clientY),o=Q(e,r,i,c),n=V??new Set,s=new Set(o);let y=0;for(const v of s)n.has(v)&&y++;let d="disjoint";y===0?d="disjoint":y===s.size&&y===n.size?d="equal":y===s.size||y===n.size?d="containment":d="partial";const u=!j&&(d==="partial"||!U&&d==="containment"),h=!H&&n.size>0&&o.length>0;if(u||h){A(n),V=null,N();return}const m=Yt(n,o,Et);if(A(m),B&&o.length>0){const v=zt(o);if(v!==null){try{console.warn(`重复编组被阻止:与已存在的第${v+1}组元素完全一致`)}catch{}V=null,N();return}a.push(o),k=a.length-1,I.push(!1),Y.push(St());const b=new Set;a.forEach(l=>l.forEach(f=>b.add(f))),A(b),L()}V=null,N()},jt=t=>{var m;if(!gt||!B)return;const e=t.target;if(!e)return;let r=e;if(Nt&&(r=((m=e.closest)==null?void 0:m.call(e,Nt))||null),!r||!O.contains(r))return;const i=r.getBoundingClientRect(),c=Q(i.left,i.top,i.width,i.height),o=new Set(F),n=new Set(c);let s=0;for(const v of n)o.has(v)&&s++;let y="disjoint";s===0?y="disjoint":s===n.size&&s===o.size?y="equal":s===n.size||s===o.size?y="containment":y="partial";const d=!j&&(y==="partial"||!U&&y==="containment"),u=!H&&o.size>0&&c.length>0;if(c.length===0||d||u){N();return}const h=zt(c);if(h!==null){try{console.warn(`重复编组被阻止:与已存在的第${h+1}组元素完全一致`)}catch{}N();return}a.push(c),k=a.length-1,I.push(!1),Y.push(St());const g=new Set;a.forEach(v=>v.forEach(b=>g.add(b))),A(g),L(),N()},Ht=()=>rt(null);function Q(t,e,r,i){if(r===0||i===0)return[];const c=O.getBoundingClientRect(),o=new DOMRect(t,e,r,i);if(!it(o,c))return[];const n=Array.from(O.querySelectorAll(ut));let s=[];const y=new Map;for(const u of n){if(bt(u))continue;const h=u.getBoundingClientRect();if(!it(h,c))continue;let g=!1;if(pt==="contains")g=ne(o,h);else if(pt==="center"){const m=h.left+h.width/2,v=h.top+h.height/2;g=m>=o.left&&m<=o.right&&v>=o.top&&v<=o.bottom}else it(o,h)&&(g=Ft(o,h)>=Math.max(0,Math.min(1,Kt)));if(g){const m=pt==="contains"?1:Ft(o,h);y.set(u,m),s.push(u)}}const d=Qt??(Jt?"leaf":"none");if(d!=="none"&&s.length>1){if(d==="leaf")s=s.filter(u=>!s.some(h=>h!==u&&u.contains(h)));else if(d==="best"){const u=[...s].sort((g,m)=>(y.get(m)||0)-(y.get(g)||0)),h=[];for(const g of u)h.find(v=>v.contains(g)||g.contains(v))||h.push(g);s=h}}return s}document.addEventListener("mousedown",Dt,!0),document.addEventListener("mousemove",Tt),document.addEventListener("mouseup",Xt),ot&&O.addEventListener("mouseleave",Ht),B&>&&O.addEventListener("dblclick",jt);const ct=()=>L();B&&(window.addEventListener("scroll",ct,!0),window.addEventListener("resize",ct));const at=()=>{if(B){const t=a.map(o=>Mt(o)),e=Array(a.length).fill(null),r=t.map(o=>o?Math.max(0,o.width*o.height):Number.POSITIVE_INFINITY);for(let o=0;o<a.length;o++){const n=t[o];if(!n)continue;let s=null,y=Number.POSITIVE_INFINITY;for(let d=0;d<a.length;d++){if(o===d)continue;const u=t[d];if(!u)continue;if(u.left<=n.left&&u.top<=n.top&&u.left+u.width>=n.left+n.width&&u.top+u.height>=n.top+n.height){const g=Number(r[d]);g<y&&(y=g,s=d)}}e[o]=s}const i=Array.from({length:a.length},()=>[]);for(let o=0;o<a.length;o++){const n=e[o];n!=null&&i[n]&&i[n].push(o)}const c=[];for(let o=0;o<a.length;o++)(e[o]===null||e[o]===void 0)&&c.push(o);return{type:"groups",groups:a.map(o=>o.slice()),flat:Array.from(F),hidden:I.slice(),groupRects:t,groupNesting:{parents:e,children:i,roots:c}}}return{type:"single",selected:Array.from(F)}},N=()=>{const t=at();if(Lt)try{Lt(t)}catch{}for(const r of K)try{r(t)}catch{}const e=Ct.splice(0);for(const r of e)try{r(t)}catch{}},Ut={destroy(){document.removeEventListener("mousedown",Dt),document.removeEventListener("mousemove",Tt),document.removeEventListener("mouseup",Xt),z&&z.parentNode&&z.parentNode.removeChild(z),z=null,O.querySelectorAll(`.${et}`).forEach(e=>e.classList.remove(et)),ot&&(O.removeEventListener("mouseleave",Ht),rt(null)),B&&(window.removeEventListener("scroll",ct,!0),window.removeEventListener("resize",ct)),B&>&&O.removeEventListener("dblclick",jt),J(),a.forEach(e=>e.forEach(r=>r.style.visibility="")),a=[],I=[],Y=[],k=null,F.clear(),K.splice(0),Ct.splice(0)},getGroups(){return a.slice()},clearGroups(){a.forEach(e=>e.forEach(r=>r.style.visibility="")),a=[],I=[],Y=[],k=null,J(),A(new Set)},removeGroup(t){return Pt(t)},addGroup(t){return re(t)},setGroupVisibility(t,e){return lt(t,e)},toggleGroupVisibility(t){return t<0||t>=a.length?!1:(I[t]=!I[t],Bt(t),L(),!0)},getSelectionResult(){return at()},refresh(){L()},hideOverlays(){J()},showAndRefreshOverlays(){L()},getGroupNesting(){const t=at();return t.type==="groups"?t.groupNesting:null},onSelectionEnd(t){return K.push(t),()=>{const e=K.indexOf(t);e>=0&&K.splice(e,1)}},waitForSelectionEnd(){return new Promise(t=>{Ct.push(t)})}};return Gt=Ut,Ut}D.default=X,D.marqueeSelection=X,Object.defineProperties(D,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
|
|
2
|
+
//# sourceMappingURL=marquee-selection.umd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"marquee-selection.umd.js","sources":["../src/marqueeSelection.ts"],"sourcesContent":["// 矩形拖拽圈选:在指定容器内,按住鼠标左键拖拽绘制选择框,选中与之相交/包含的子元素\n// 公开一个启用函数,返回用于卸载的 destroy 方法\n\nexport type MarqueeSelectionOptions = {\n // 选择框的父容器,仅在该容器内触发与计算\n container: HTMLElement;\n // 在容器内可被圈选的元素选择器,默认 img\n selectable?: string;\n // 不参与圈选与悬浮高亮的元素(CSS 选择器,单个或数组)。\n // 常见用法:排除 InfiniteCanvas 包裹用的 content 或顶层容器,例如 ['.stage-content', '#container']\n exclude?: string | string[];\n // 选择规则:与框相交 or 完全包含\n selectionMode?: \"intersects\" | \"contains\" | \"center\";\n // 当 selectionMode 为 intersects 时,要求被选中元素与选择框的重叠面积 / 元素自身面积 >= 此阈值(0~1),用于避免轻微擦边命中\n minOverlapRatio?: number;\n // 重叠度计算指标:'element' => 重叠面积/元素面积;'iou' => 交并比,更均衡\n overlapMetric?: \"element\" | \"iou\";\n // 选中样式类名\n selectedClass?: string;\n // 框选变化回调(单选/编组)\n onChange?: (\n payload:\n | { type: \"single\"; selected: Element[] }\n | { type: \"groups\"; groups: Element[][]; flat: Element[] }\n ) => void;\n // 如果一个元素和其后代都命中,是否移除祖先,仅保留叶子节点(默认 true,避免选中大父容器)\n preventAncestorSelection?: boolean;\n // 父子同时命中时的冲突处理:\n // - 'none' 不处理(父子并存)\n // - 'leaf' 仅保留叶子(等同 preventAncestorSelection=true)\n // - 'best' 每条祖先链保留得分更高者(推荐)\n conflictStrategy?: \"none\" | \"leaf\" | \"best\";\n // 多次圈选:是否累积选择(默认 false)。true 时本次拖拽将与已有选择集合合并。\n multi?: boolean;\n // 多次圈选合并模式:\n // - 'replace' 仅保留本次命中\n // - 'add' 将本次命中加入已有集合\n // - 'subtract'从已有集合移除本次命中\n // - 'toggle' 对本次命中做切换(有则去,无则加)\n // - 'auto' 根据按键:Shift=add,Alt=subtract,Meta/Ctrl=toggle,默认 add\n combineMode?: \"replace\" | \"add\" | \"subtract\" | \"toggle\" | \"auto\";\n // 编组模式:每次 mouseup 将本次命中作为一组,并渲染组外框\n groupMode?: boolean;\n // 组外框类名(可自定义样式),默认使用内联样式\n groupOverlayClass?: string;\n // 组主题颜色:用于组外框描边与工具栏背景。\n // - 若提供字符串,则所有组使用该颜色(如 '#3b82f6' / 'hsl(215,90%,57%)' / 'rgba(59,130,246,.9)')。\n // - 若不提供且 groupRandomColor=true,则为每个新组随机生成一个柔和色。\n // - 也可提供 groupColorPalette 与 groupRandomColor 搭配使用。\n groupColor?: string;\n // 是否为每个新组随机生成颜色(默认 false)。\n groupRandomColor?: boolean;\n // 随机/轮换可选调色板(提供时将优先从此列表取色;否则使用内置的柔和色生成)。\n groupColorPalette?: string[];\n // 是否启用鼠标悬浮高亮(默认 false)\n hoverHighlight?: boolean;\n // 悬浮高亮类名(默认 'hovered')\n hoverClass?: string;\n // 拖拽结束回调:返回一次完整快照(等价于 controller.getSelectionResult() 的值)\n onSelectionEnd?: (snapshot: MarqueeSelectionSnapshot) => void;\n // 双击快速成组:双击元素时,以其外框为选择区域,快速生成一组(默认 false)\n quickGroupOnDblClick?: boolean;\n // 双击触发元素的筛选选择器(可选)。若提供,则仅当双击目标的最近祖先匹配该选择器时才触发;\n // 未提供时,使用双击目标元素自身。\n quickGroupSelector?: string;\n // 是否支持“交集圈选”(默认 true)。false 则新组与已有选择的元素集合不能有交集;\n // 注意:交集与“并集模式”不同,禁用交集不影响并集聚合能力。\n allowIntersectionSelection?: boolean;\n // 当 allowIntersectionSelection = false 时,是否仍允许“完全包含”关系(父子):\n // 即命中集合是现有集合的子集/父集(不属于部分交叉)。默认 true 允许,仅禁止“部分相交”。\n // 设为 false 则同样禁止包含关系(仅允许完全不相交或完全相等)。\n allowContainmentSelection?: boolean;\n // 是否支持“并集圈选”(默认 true)。false 则在已有选择存在时,禁止新增圈选(包括与其相交或包含的情况)。\n allowUnionSelection?: boolean;\n // 自定义工具栏按钮:会追加到每个组的工具栏\n toolbarButtons?: Array<{\n label: string; // 按钮文本\n title?: string; // 鼠标提示\n className?: string; // 附加类名\n onClick?: (ctx: {\n index: number; // 组索引\n group: Element[]; // 该组元素\n controller: MarqueeSelectionController; // 控制器\n getSnapshot: () => MarqueeSelectionSnapshot; // 获取最新快照\n refresh: () => void; // 触发重绘覆盖层并广播 onSelectionEnd\n mouseX?: number; // 触发点击时的鼠标 X(client)\n mouseY?: number; // 触发点击时的鼠标 Y(client)\n anchorRect?: DOMRect; // 工具栏矩形(可用于定位)\n anchorEl?: HTMLElement; // 工具栏元素\n overlayEl?: HTMLElement; // 覆盖层元素\n }) => void;\n }>;\n};\n\nexport type MarqueeSelectionSnapshot =\n | { type: \"single\"; selected: Element[] }\n | {\n type: \"groups\";\n groups: Element[][];\n flat: Element[];\n hidden: boolean[];\n groupRects: ({\n left: number;\n top: number;\n width: number;\n height: number;\n } | null)[];\n // 组级嵌套(按组外接矩形包含关系)\n groupNesting: {\n parents: (number | null)[]; // 每个组的最近父组索引(若无则为 null)\n children: number[][]; // 每个组的直接子组索引列表\n roots: number[]; // 无父组的组索引\n };\n };\n\nexport type MarqueeSelectionController = {\n destroy: () => void;\n getGroups: () => Element[][];\n clearGroups: () => void;\n removeGroup: (index: number) => boolean;\n // 编程式新增一组:将给定元素集合加入为新组(仅在 groupMode 下有效)。\n // 返回值:true 表示创建成功;false 表示因配置限制/重复/无效元素而未创建。\n addGroup: (elements: Element[]) => boolean;\n setGroupVisibility: (index: number, hidden: boolean) => boolean;\n toggleGroupVisibility: (index: number) => boolean;\n getSelectionResult: () => MarqueeSelectionSnapshot;\n // 仅重绘覆盖层(适用于外部视图变换后刷新)\n refresh: () => void;\n // 隐藏覆盖层(用于进行视图变换时临时隐藏)\n hideOverlays: () => void;\n // 显示并重绘覆盖层(变换结束后调用)\n showAndRefreshOverlays: () => void;\n // 订阅下一次拖拽结束(持续订阅)\n onSelectionEnd: (\n handler: (snapshot: MarqueeSelectionSnapshot) => void\n ) => () => void;\n // 等待下一次拖拽结束(一次性)\n waitForSelectionEnd: () => Promise<MarqueeSelectionSnapshot>;\n // 获取当前组级嵌套信息(仅 groupMode 下有效,其他返回 null)\n getGroupNesting: () => {\n parents: (number | null)[];\n children: number[][];\n roots: number[];\n } | null;\n};\n\n/**\n * 启用容器内矩形拖拽圈选\n */\nexport function marqueeSelection(\n options: MarqueeSelectionOptions\n): MarqueeSelectionController {\n const {\n container,\n selectable = \"img\",\n exclude,\n selectionMode = \"intersects\",\n minOverlapRatio = 0,\n overlapMetric = \"element\",\n selectedClass = \"selected\",\n onChange,\n preventAncestorSelection = true,\n conflictStrategy,\n groupMode = false,\n groupOverlayClass,\n groupColor,\n groupRandomColor = false,\n groupColorPalette,\n multi = false,\n combineMode,\n hoverHighlight = false,\n hoverClass = \"hovered\",\n onSelectionEnd: onSelectionEndOption,\n quickGroupOnDblClick = false,\n quickGroupSelector,\n allowIntersectionSelection = true,\n allowUnionSelection = true,\n allowContainmentSelection = true,\n toolbarButtons,\n } = options;\n // 归一化排除选择器\n const excludeSelectors: string[] = Array.isArray(exclude)\n ? (exclude.filter(Boolean) as string[])\n : exclude\n ? [exclude]\n : [];\n const isExcluded = (el: Element | null | undefined): boolean => {\n if (!el || !excludeSelectors.length) return false;\n for (const sel of excludeSelectors) {\n try {\n if (el instanceof Element && el.matches(sel)) return true;\n } catch {}\n }\n return false;\n };\n\n if (!container) throw new Error(\"container is required\");\n\n // 内部状态\n let startX = 0;\n let startY = 0;\n let isDragging = false;\n let marqueeEl: HTMLDivElement | null = null;\n let dragInvalid = false; // 当前拖拽是否因配置被判定为无效(红框提示)\n // 已应用到 DOM 的当前选择集合\n let selectedSet = new Set<Element>();\n // 当前拖拽前的基线集合(用于多次圈选)\n let baseSet: Set<Element> | null = null;\n // 当前拖拽的合并模式\n let dragCombine: \"replace\" | \"add\" | \"subtract\" | \"toggle\" = \"replace\";\n // 编组数据与覆盖层\n let groups: Element[][] = [];\n let groupOverlays: HTMLDivElement[] = [];\n // 组可见性状态\n let groupHidden: boolean[] = [];\n // 组主题颜色(与 groups 等长)\n let groupColors: string[] = [];\n\n // 获取一个新组的主题色\n const pickPastel = () => {\n const h = Math.floor(Math.random() * 360);\n const s = 70;\n const l = 55;\n return `hsl(${h}, ${s}%, ${l}%)`;\n };\n const getNewGroupColor = (): string => {\n if (groupColor && typeof groupColor === \"string\")\n return groupColor as string;\n if (groupRandomColor) {\n if (Array.isArray(groupColorPalette) && groupColorPalette.length > 0) {\n const idx = Math.floor(Math.random() * groupColorPalette.length);\n return groupColorPalette[idx]!;\n }\n return pickPastel();\n }\n return \"rgba(255, 165, 0, 0.9)\";\n };\n // 最近一次新建的组索引(用于显示合并按钮)\n let lastCreatedGroupIndex: number | null = null;\n // 拖拽结束事件\n const endListeners: Array<(s: MarqueeSelectionSnapshot) => void> = [];\n const endWaiters: Array<(s: MarqueeSelectionSnapshot) => void> = [];\n // 组框调整尺寸会话\n type ResizeSide =\n | \"left\"\n | \"right\"\n | \"top\"\n | \"bottom\"\n | \"nw\"\n | \"ne\"\n | \"sw\"\n | \"se\";\n let resizeSession: null | {\n idx: number;\n side: ResizeSide;\n startX: number;\n startY: number;\n startRect: { left: number; top: number; width: number; height: number };\n overlay: HTMLDivElement;\n } = null;\n // 判断命中元素是否与已存在的某个组完全一致,返回组索引或 null\n const findDuplicateGroupIndex = (els: Element[]): number | null => {\n if (!els.length) return null;\n const target = new Set<Element>(els);\n for (let i = 0; i < groups.length; i++) {\n const g = groups[i] || [];\n if (g.length !== target.size) continue;\n let same = true;\n // 将当前组转为集合便于比较\n const gs = new Set<Element>(g);\n if (gs.size !== target.size) {\n same = false;\n }\n if (same) {\n for (const el of target) {\n if (!gs.has(el)) {\n same = false;\n break;\n }\n }\n }\n if (same) return i;\n }\n return null;\n };\n\n // 提前声明控制器引用,便于在内部回调中访问\n let controllerRef: MarqueeSelectionController | null = null;\n\n const applyGroupVisibility = (index: number) => {\n const hidden = !!groupHidden[index];\n const els = groups[index] || [];\n for (const el of els) {\n (el as HTMLElement).style.visibility = hidden ? \"hidden\" : \"\";\n }\n };\n\n const setGroupHidden = (index: number, hidden: boolean) => {\n if (index < 0 || index >= groups.length) return false;\n groupHidden[index] = hidden;\n applyGroupVisibility(index);\n return true;\n };\n // 悬浮高亮\n let hoveredEl: Element | null = null;\n\n const setHovered = (el: Element | null) => {\n if (!hoverHighlight) return;\n if (hoveredEl && hoveredEl !== el) {\n hoveredEl.classList.remove(hoverClass);\n }\n if (el && hoveredEl !== el) {\n el.classList.add(hoverClass);\n }\n hoveredEl = el;\n };\n\n // 创建并样式化选择框(添加到 body,避免容器 overflow 或层级影响)\n const createMarquee = () => {\n const el = document.createElement(\"div\");\n el.style.position = \"fixed\";\n el.style.left = \"0px\";\n el.style.top = \"0px\";\n el.style.width = \"0px\";\n el.style.height = \"0px\";\n el.style.outline = \"1px dashed #268aff\";\n el.style.background = \"rgba(38,138,255,0.12)\";\n el.style.pointerEvents = \"none\";\n el.style.zIndex = \"2147483647\"; // 置顶\n el.style.boxSizing = \"border-box\";\n document.body.appendChild(el);\n return el;\n };\n\n // 工具:计算两个矩形是否相交/包含\n const rectIntersects = (a: DOMRect, b: DOMRect) =>\n a.left < b.right &&\n a.right > b.left &&\n a.top < b.bottom &&\n a.bottom > b.top;\n const rectContains = (outer: DOMRect, inner: DOMRect) =>\n outer.left <= inner.left &&\n outer.right >= inner.right &&\n outer.top <= inner.top &&\n outer.bottom >= inner.bottom;\n\n // 重叠面积 / 元素面积\n const overlapRatio = (a: DOMRect, b: DOMRect): number => {\n const left = Math.max(a.left, b.left);\n const right = Math.min(a.right, b.right);\n const top = Math.max(a.top, b.top);\n const bottom = Math.min(a.bottom, b.bottom);\n const w = Math.max(0, right - left);\n const h = Math.max(0, bottom - top);\n const overlap = w * h;\n const areaB = Math.max(1, b.width * b.height); // 避免除 0\n return overlap / areaB;\n };\n\n // IoU:重叠面积 / 并集面积\n const iouRatio = (a: DOMRect, b: DOMRect): number => {\n const left = Math.max(a.left, b.left);\n const right = Math.min(a.right, b.right);\n const top = Math.max(a.top, b.top);\n const bottom = Math.min(a.bottom, b.bottom);\n const w = Math.max(0, right - left);\n const h = Math.max(0, bottom - top);\n const inter = w * h;\n const areaA = Math.max(1, a.width * a.height);\n const areaB = Math.max(1, b.width * b.height);\n const union = areaA + areaB - inter;\n return inter / union;\n };\n\n const getRatio = (marqueeRect: DOMRect, elementRect: DOMRect): number =>\n overlapMetric === \"iou\"\n ? iouRatio(marqueeRect, elementRect)\n : overlapRatio(marqueeRect, elementRect);\n\n // 工具:获取当前选择框 rect(基于 client 坐标)\n const getCurrentMarqueeRect = (\n x1: number,\n y1: number,\n x2: number,\n y2: number\n ): { left: number; top: number; width: number; height: number } => {\n const left = Math.min(x1, x2);\n const top = Math.min(y1, y2);\n const width = Math.abs(x2 - x1);\n const height = Math.abs(y2 - y1);\n return { left, top, width, height };\n };\n\n // 组外框计算与渲染\n const calcGroupRect = (\n els: Element[]\n ): { left: number; top: number; width: number; height: number } | null => {\n const rects = els\n .map((el) => el.getBoundingClientRect())\n .filter((r) => r.width > 0 && r.height > 0);\n if (!rects.length) return null;\n const left = Math.min(...rects.map((r) => r.left));\n const top = Math.min(...rects.map((r) => r.top));\n const right = Math.max(...rects.map((r) => r.right));\n const bottom = Math.max(...rects.map((r) => r.bottom));\n return { left, top, width: right - left, height: bottom - top };\n };\n\n const clearGroupOverlays = () => {\n groupOverlays.forEach((el) => el.remove());\n groupOverlays = [];\n };\n\n const renderGroupOverlays = () => {\n clearGroupOverlays();\n if (!groupMode) return;\n // 已放置的工具栏矩形(用于避让)\n const placedToolbarRects: Array<{\n left: number;\n top: number;\n right: number;\n bottom: number;\n }> = [];\n const rectsOverlap = (\n a: { left: number; top: number; right: number; bottom: number },\n b: { left: number; top: number; right: number; bottom: number }\n ) =>\n a.left < b.right &&\n a.right > b.left &&\n a.top < b.bottom &&\n a.bottom > b.top;\n\n groups.forEach((g, idx) => {\n const box = calcGroupRect(g);\n if (!box) return;\n const color = groupColors[idx] || \"rgba(255, 165, 0, 0.9)\";\n const el = document.createElement(\"div\");\n el.style.position = \"fixed\";\n el.style.pointerEvents = \"none\"; // 覆盖层本体不拦截,下面的工具条与句柄可交互\n el.style.zIndex = \"2147483646\";\n el.style.left = `${box.left}px`;\n el.style.top = `${box.top}px`;\n el.style.width = `${box.width}px`;\n el.style.height = `${box.height}px`;\n el.style.boxSizing = \"border-box\";\n el.style.outline = `1px solid ${color}`;\n el.style.background = \"transparent\";\n // 先挂载到 DOM,便于测量内部工具栏尺寸与布局\n document.body.appendChild(el);\n // 工具条(可交互),置于标签位置\n const toolbar = document.createElement(\"div\");\n toolbar.style.position = \"absolute\";\n // 初始位置将由 placeToolbar 决定\n toolbar.style.display = \"inline-flex\";\n toolbar.style.alignItems = \"center\";\n toolbar.style.gap = \"6px\";\n // 优化:避免工具栏过宽撑破容器\n toolbar.style.minWidth = \"max-content\";\n toolbar.style.padding = \"2px 6px\";\n toolbar.style.fontSize = \"12px\";\n toolbar.style.lineHeight = \"16px\";\n toolbar.style.color = \"#fff\";\n toolbar.style.background = color;\n toolbar.style.borderRadius = \"4px\";\n toolbar.style.pointerEvents = \"auto\"; // 工具条可点\n\n const label = document.createElement(\"span\");\n label.textContent = `组 ${idx + 1}`;\n\n const toggleBtn = document.createElement(\"button\");\n toggleBtn.textContent = groupHidden[idx] ? \"显示\" : \"隐藏\";\n toggleBtn.style.background = \"rgba(0,0,0,0.15)\";\n toggleBtn.style.border = \"none\";\n toggleBtn.style.color = \"#fff\";\n toggleBtn.style.padding = \"2px 6px\";\n toggleBtn.style.borderRadius = \"3px\";\n toggleBtn.style.cursor = \"pointer\";\n toggleBtn.onclick = (ev) => {\n ev.stopPropagation();\n setGroupHidden(idx, !groupHidden[idx]);\n renderGroupOverlays(); // 刷新按钮文案\n // 通知外部:可用于刷新结果面板(hidden 状态改变)\n notifySelectionEnd();\n };\n\n const removeBtn = document.createElement(\"button\");\n removeBtn.textContent = \"取消组\";\n removeBtn.style.background = \"rgba(0,0,0,0.15)\";\n removeBtn.style.border = \"none\";\n removeBtn.style.color = \"#fff\";\n removeBtn.style.padding = \"2px 6px\";\n removeBtn.style.borderRadius = \"3px\";\n removeBtn.style.cursor = \"pointer\";\n removeBtn.onclick = (ev) => {\n ev.stopPropagation();\n // 移除前恢复可见,避免遗留隐藏样式\n setGroupHidden(idx, false);\n removeGroupAt(idx);\n };\n\n toolbar.appendChild(label);\n toolbar.appendChild(toggleBtn);\n toolbar.appendChild(removeBtn);\n\n // 若该组为最近创建,且与其他组发生矩形相交,则显示“合并”按钮\n const getIntersectingIndices = (selfIdx: number): number[] => {\n const selfRect = box\n ? new DOMRect(box.left, box.top, box.width, box.height)\n : null;\n if (!selfRect) return [];\n const list: number[] = [];\n groups.forEach((og, j) => {\n if (j === selfIdx) return;\n const ob = calcGroupRect(og);\n if (!ob) return;\n const orect = new DOMRect(ob.left, ob.top, ob.width, ob.height);\n if (rectIntersects(selfRect, orect)) list.push(j);\n });\n return list;\n };\n\n const maybeAddMergeButton = () => {\n if (lastCreatedGroupIndex !== idx) return;\n const ints = getIntersectingIndices(idx);\n if (ints.length === 0) return;\n const mergeBtn = document.createElement(\"button\");\n mergeBtn.textContent = \"合并\";\n mergeBtn.style.background = \"rgba(0,0,0,0.15)\";\n mergeBtn.style.border = \"none\";\n mergeBtn.style.color = \"#fff\";\n mergeBtn.style.padding = \"2px 6px\";\n mergeBtn.style.borderRadius = \"3px\";\n mergeBtn.style.cursor = \"pointer\";\n\n const openPanel = () => {\n // 如果已存在面板,先移除\n const old = toolbar.querySelector(\".merge-panel\");\n if (old) old.remove();\n const panel = document.createElement(\"div\");\n panel.className = \"merge-panel\";\n panel.style.position = \"absolute\";\n panel.style.left = \"0\";\n panel.style.top = \"22px\"; // 工具条下方\n panel.style.minWidth = \"160px\";\n panel.style.padding = \"8px\";\n panel.style.background = \"#fff\";\n panel.style.color = \"#333\";\n panel.style.border = \"1px solid rgba(0,0,0,0.15)\";\n panel.style.borderRadius = \"6px\";\n panel.style.boxShadow = \"0 4px 12px rgba(0,0,0,0.15)\";\n panel.style.pointerEvents = \"auto\";\n panel.style.zIndex = \"2147483647\";\n\n const title = document.createElement(\"div\");\n title.textContent = \"选择要合并的组\";\n title.style.fontSize = \"12px\";\n title.style.marginBottom = \"6px\";\n panel.appendChild(title);\n\n const listWrap = document.createElement(\"div\");\n listWrap.style.maxHeight = \"200px\";\n listWrap.style.overflow = \"auto\";\n const checkboxRefs: HTMLInputElement[] = [];\n ints.forEach((j) => {\n const row = document.createElement(\"label\");\n row.style.display = \"flex\";\n row.style.alignItems = \"center\";\n row.style.gap = \"6px\";\n row.style.fontSize = \"12px\";\n row.style.margin = \"4px 0\";\n const cb = document.createElement(\"input\");\n cb.type = \"checkbox\";\n cb.checked = true;\n cb.value = String(j);\n const txt = document.createElement(\"span\");\n txt.textContent = `组 ${j + 1}`;\n row.appendChild(cb);\n row.appendChild(txt);\n listWrap.appendChild(row);\n checkboxRefs.push(cb);\n });\n panel.appendChild(listWrap);\n\n const actions = document.createElement(\"div\");\n actions.style.display = \"flex\";\n actions.style.gap = \"8px\";\n actions.style.marginTop = \"8px\";\n const ok = document.createElement(\"button\");\n ok.textContent = \"确认\";\n ok.style.padding = \"2px 8px\";\n ok.style.cursor = \"pointer\";\n const cancel = document.createElement(\"button\");\n cancel.textContent = \"取消\";\n cancel.style.padding = \"2px 8px\";\n cancel.style.cursor = \"pointer\";\n actions.appendChild(ok);\n actions.appendChild(cancel);\n panel.appendChild(actions);\n\n cancel.onclick = (ev) => {\n ev.stopPropagation();\n panel.remove();\n };\n ok.onclick = (ev) => {\n ev.stopPropagation();\n const chosen = checkboxRefs\n .filter((c) => c.checked)\n .map((c) => parseInt(c.value, 10))\n .filter((n) => !Number.isNaN(n));\n if (chosen.length === 0) {\n panel.remove();\n return;\n }\n // 合并逻辑:将选中组与当前组求并集,替换当前组,并移除被合并的组\n const union = new Set<Element>();\n const base = groups[idx] || [];\n base.forEach((el) => union.add(el));\n chosen.forEach((ci) => {\n const arr = groups[ci] || [];\n arr.forEach((el) => union.add(el));\n });\n groups[idx] = Array.from(union);\n // 被合并组若处于隐藏,先恢复可见再删除\n const sorted = [...chosen].sort((a, b) => b - a);\n let newIdx = idx;\n sorted.forEach((ri) => {\n if (ri < 0 || ri >= groups.length || ri === idx) return;\n setGroupHidden(ri, false);\n groups.splice(ri, 1);\n groupHidden.splice(ri, 1);\n groupColors.splice(ri, 1);\n if (lastCreatedGroupIndex !== null) {\n if (lastCreatedGroupIndex === ri) lastCreatedGroupIndex = null;\n else if (lastCreatedGroupIndex > ri) lastCreatedGroupIndex--;\n }\n if (ri < newIdx) newIdx--;\n });\n // 合并结果保留在(调整后的)当前组位置,并作为“最近创建”以便继续合并\n lastCreatedGroupIndex = newIdx;\n // 刷新 UI 与选择\n const unionSel = new Set<Element>();\n groups.forEach((g) => g.forEach((el) => unionSel.add(el)));\n updateDomSelection(unionSel);\n renderGroupOverlays();\n panel.remove();\n notifySelectionEnd();\n };\n\n toolbar.appendChild(panel);\n };\n\n mergeBtn.onclick = (ev) => {\n ev.stopPropagation();\n openPanel();\n };\n toolbar.appendChild(mergeBtn);\n };\n maybeAddMergeButton();\n el.appendChild(toolbar);\n\n // 追加自定义工具栏按钮\n if (toolbarButtons && toolbarButtons.length) {\n const addCustomButton = (\n cfg: NonNullable<MarqueeSelectionOptions[\"toolbarButtons\"]>[number]\n ) => {\n const btn = document.createElement(\"button\");\n btn.textContent = cfg.label || \"按钮\";\n btn.title = cfg.title || \"\";\n btn.style.background = \"rgba(0,0,0,0.15)\";\n btn.style.border = \"none\";\n btn.style.color = \"#fff\";\n btn.style.padding = \"2px 6px\";\n btn.style.borderRadius = \"3px\";\n btn.style.cursor = \"pointer\";\n if (cfg.className)\n btn.className += (btn.className ? \" \" : \"\") + cfg.className;\n btn.onclick = (ev) => {\n ev.stopPropagation();\n try {\n cfg.onClick?.({\n index: idx,\n group: groups[idx] || [],\n controller: controllerRef as MarqueeSelectionController,\n getSnapshot: () => buildSnapshot(),\n refresh: () => {\n renderGroupOverlays();\n notifySelectionEnd();\n },\n mouseX: (ev as MouseEvent).clientX,\n mouseY: (ev as MouseEvent).clientY,\n anchorRect: toolbar.getBoundingClientRect(),\n anchorEl: toolbar,\n overlayEl: el,\n });\n } catch {}\n };\n toolbar.appendChild(btn);\n };\n toolbarButtons.forEach(addCustomButton);\n }\n\n // 工具:将工具栏放置到避免重叠的位置(尝试四角 + 台阶偏移)\n const placeToolbar = () => {\n const anchors: Array<\"tl\" | \"tr\" | \"bl\" | \"br\"> = [\n \"tl\",\n \"tr\",\n \"bl\",\n \"br\",\n ];\n // 隐藏以避免闪烁\n const prevVisibility = toolbar.style.visibility;\n toolbar.style.visibility = \"hidden\";\n const step = 28; // 纵向台阶高度\n const margin = 6; // 与外框的间距\n // 尝试不同锚点 + 若干台阶偏移\n outer: for (let a = 0; a < anchors.length; a++) {\n for (let k = 0; k < 6; k++) {\n // 重置定位\n toolbar.style.left = \"\";\n toolbar.style.right = \"\";\n toolbar.style.top = \"\";\n toolbar.style.bottom = \"\";\n const h = toolbar.offsetHeight || 22;\n if (anchors[a] === \"tl\") {\n toolbar.style.left = \"0\";\n toolbar.style.top = `${-h - margin + k * step}px`;\n } else if (anchors[a] === \"tr\") {\n toolbar.style.right = \"0\";\n toolbar.style.top = `${-h - margin + k * step}px`;\n } else if (anchors[a] === \"bl\") {\n toolbar.style.left = \"0\";\n toolbar.style.top = `${box.height + margin + k * step}px`;\n } else {\n toolbar.style.right = \"0\";\n toolbar.style.top = `${box.height + margin + k * step}px`;\n }\n const r = toolbar.getBoundingClientRect();\n const rect = {\n left: r.left,\n top: r.top,\n right: r.right,\n bottom: r.bottom,\n };\n // 不再基于视口上边界进行约束检查,允许工具栏在可见区域之外放置(与 AI 浮层一致)\n // 与已放置的工具栏避免重叠\n let collide = false;\n for (const pr of placedToolbarRects) {\n if (rectsOverlap(rect, pr)) {\n collide = true;\n break;\n }\n }\n if (!collide) {\n placedToolbarRects.push(rect);\n break outer;\n }\n }\n }\n toolbar.style.visibility = prevVisibility;\n };\n placeToolbar();\n\n // 悬停工具条将对应覆盖层置顶,便于在重叠场景下切换\n toolbar.addEventListener(\"mouseenter\", () => {\n try {\n groupOverlays.forEach((ov) => (ov.style.zIndex = \"2147483646\"));\n el.style.zIndex = \"2147483647\";\n } catch {}\n });\n\n // 边缘与四角拖拽句柄\n const addHandle = (side: ResizeSide) => {\n const h = document.createElement(\"div\");\n h.style.position = \"absolute\";\n h.style.pointerEvents = \"auto\";\n h.style.background = \"transparent\";\n h.style.zIndex = \"2147483647\";\n const thickness = 8; // 命中区域\n if (side === \"top\") {\n h.style.cursor = \"ns-resize\";\n h.style.left = \"-4px\";\n h.style.right = \"-4px\";\n h.style.top = `-${(thickness / 2) | 0}px`;\n h.style.height = `${thickness}px`;\n } else if (side === \"bottom\") {\n h.style.cursor = \"ns-resize\";\n h.style.left = \"-4px\";\n h.style.right = \"-4px\";\n h.style.bottom = `-${(thickness / 2) | 0}px`;\n h.style.height = `${thickness}px`;\n } else if (side === \"left\") {\n h.style.cursor = \"ew-resize\";\n h.style.top = \"-4px\";\n h.style.bottom = \"-4px\";\n h.style.left = `-${(thickness / 2) | 0}px`;\n h.style.width = `${thickness}px`;\n } else if (side === \"right\") {\n h.style.cursor = \"ew-resize\";\n h.style.top = \"-4px\";\n h.style.bottom = \"-4px\";\n h.style.right = `-${(thickness / 2) | 0}px`;\n h.style.width = `${thickness}px`;\n } else if (side === \"nw\") {\n h.style.cursor = \"nwse-resize\";\n h.style.left = `-${(thickness / 2) | 0}px`;\n h.style.top = `-${(thickness / 2) | 0}px`;\n h.style.width = `${thickness}px`;\n h.style.height = `${thickness}px`;\n } else if (side === \"ne\") {\n h.style.cursor = \"nesw-resize\";\n h.style.right = `-${(thickness / 2) | 0}px`;\n h.style.top = `-${(thickness / 2) | 0}px`;\n h.style.width = `${thickness}px`;\n h.style.height = `${thickness}px`;\n } else if (side === \"sw\") {\n h.style.cursor = \"nesw-resize\";\n h.style.left = `-${(thickness / 2) | 0}px`;\n h.style.bottom = `-${(thickness / 2) | 0}px`;\n h.style.width = `${thickness}px`;\n h.style.height = `${thickness}px`;\n } else if (side === \"se\") {\n h.style.cursor = \"nwse-resize\";\n h.style.right = `-${(thickness / 2) | 0}px`;\n h.style.bottom = `-${(thickness / 2) | 0}px`;\n h.style.width = `${thickness}px`;\n h.style.height = `${thickness}px`;\n }\n h.onmousedown = (ev) => {\n ev.preventDefault();\n ev.stopPropagation();\n // 启动调整会话\n const rect = {\n left: parseFloat(el.style.left || \"0\"),\n top: parseFloat(el.style.top || \"0\"),\n width: parseFloat(el.style.width || \"0\"),\n height: parseFloat(el.style.height || \"0\"),\n };\n resizeSession = {\n idx,\n side,\n startX: (ev as MouseEvent).clientX,\n startY: (ev as MouseEvent).clientY,\n startRect: rect,\n overlay: el,\n };\n document.addEventListener(\"mousemove\", onResizeMove);\n document.addEventListener(\"mouseup\", onResizeEnd, { once: true });\n };\n el.appendChild(h);\n };\n // 四边\n addHandle(\"top\");\n addHandle(\"right\");\n addHandle(\"bottom\");\n addHandle(\"left\");\n // 四角\n addHandle(\"nw\");\n addHandle(\"ne\");\n addHandle(\"sw\");\n addHandle(\"se\");\n\n if (groupOverlayClass) el.classList.add(groupOverlayClass);\n groupOverlays.push(el);\n });\n };\n\n const onResizeMove = (e: MouseEvent) => {\n if (!resizeSession) return;\n const { idx, side, startX, startY, startRect, overlay } = resizeSession;\n const dx = e.clientX - startX;\n const dy = e.clientY - startY;\n let left = startRect.left;\n let top = startRect.top;\n let width = startRect.width;\n let height = startRect.height;\n const minSize = 4;\n if (side === \"left\" || side === \"nw\" || side === \"sw\") {\n left = startRect.left + dx;\n width = startRect.width - dx;\n if (width < minSize) {\n left = startRect.left + (startRect.width - minSize);\n width = minSize;\n }\n } else if (side === \"right\" || side === \"ne\" || side === \"se\") {\n width = startRect.width + dx;\n if (width < minSize) width = minSize;\n }\n if (side === \"top\" || side === \"nw\" || side === \"ne\") {\n top = startRect.top + dy;\n height = startRect.height - dy;\n if (height < minSize) {\n top = startRect.top + (startRect.height - minSize);\n height = minSize;\n }\n } else if (side === \"bottom\" || side === \"sw\" || side === \"se\") {\n height = startRect.height + dy;\n if (height < minSize) height = minSize;\n }\n // 更新覆盖层位置(预览区域)\n overlay.style.left = `${left}px`;\n overlay.style.top = `${top}px`;\n overlay.style.width = `${width}px`;\n overlay.style.height = `${height}px`;\n\n // 计算并实时预览该组的新命中(带约束校验)\n const hits = computeSelection(left, top, width, height);\n const currentSet = new Set<Element>(groups[idx] || []);\n const otherSet = new Set<Element>();\n groups.forEach((g, i) => {\n if (i !== idx) g.forEach((el) => otherSet.add(el));\n });\n const hitsSet = new Set<Element>(hits);\n let partialOverlapFound = false;\n let containmentFound = false; // 命中集合与某个其它组构成包含关系\n for (let i = 0; i < groups.length; i++) {\n if (i === idx) continue;\n const gSet = new Set<Element>(groups[i] || []);\n let interCount = 0;\n for (const el of hitsSet) if (gSet.has(el)) interCount++;\n if (interCount === 0) continue; // 不相交\n if (interCount === gSet.size && interCount === hitsSet.size) {\n // 完全相等 -> 视为允许(重复在其它地方处理)\n continue;\n } else if (interCount === gSet.size) {\n // 其它组完全在 hits 内\n containmentFound = true;\n } else if (interCount === hitsSet.size) {\n // hits 完全在其它组内\n containmentFound = true;\n } else {\n partialOverlapFound = true;\n break;\n }\n }\n const deltaAddCount = hits.filter((el) => !currentSet.has(el)).length;\n const violatesIntersection = !allowIntersectionSelection && (\n partialOverlapFound ||\n (!allowContainmentSelection && containmentFound)\n );\n const violatesUnion = !allowUnionSelection && deltaAddCount > 0; // 禁并集:禁止新增元素(允许减少)\n const invalid = violatesIntersection || violatesUnion;\n\n // 预览与提示:无效则保持原组不变,边框红色;有效则以 hits 预览,边框为正常橙色\n if (invalid) {\n overlay.style.outline = \"1px dashed #ff4d4f\";\n overlay.style.background = \"rgba(255,77,79,0.06)\";\n const union = new Set<Element>();\n groups.forEach((g, i) => {\n const arr = i === idx ? groups[idx] || [] : g; // 不应用 hits\n arr.forEach((el) => union.add(el));\n });\n updateDomSelection(union);\n } else {\n const color = groupColors[idx] || \"rgba(255, 165, 0, 0.9)\";\n overlay.style.outline = `1px solid ${color}`;\n overlay.style.background = \"transparent\";\n const union = new Set<Element>();\n groups.forEach((g, i) => {\n const arr = i === idx ? hits : g;\n arr.forEach((el) => union.add(el));\n });\n updateDomSelection(union);\n }\n };\n\n const onResizeEnd = (e: MouseEvent) => {\n if (!resizeSession) return;\n const { idx, overlay, startRect } =\n resizeSession as typeof resizeSession & {\n startRect: { left: number; top: number; width: number; height: number };\n };\n // 以当前 overlay 矩形为准,计算最终组命中\n const left = parseFloat(overlay.style.left || \"0\");\n const top = parseFloat(overlay.style.top || \"0\");\n const width = parseFloat(overlay.style.width || \"0\");\n const height = parseFloat(overlay.style.height || \"0\");\n const hits = computeSelection(left, top, width, height);\n // 约束校验:与其它组的交/并限制\n const currentSet = new Set<Element>(groups[idx] || []);\n const otherSet = new Set<Element>();\n groups.forEach((g, i) => {\n if (i !== idx) g.forEach((el) => otherSet.add(el));\n });\n const hitsSet = new Set<Element>(hits);\n let partialOverlapFound = false;\n let containmentFound = false;\n for (let i = 0; i < groups.length; i++) {\n if (i === idx) continue;\n const gSet = new Set<Element>(groups[i] || []);\n let interCount = 0;\n for (const el of hitsSet) if (gSet.has(el)) interCount++;\n if (interCount === 0) continue;\n if (interCount === gSet.size && interCount === hitsSet.size) {\n continue; // equal\n } else if (interCount === gSet.size || interCount === hitsSet.size) {\n containmentFound = true;\n } else {\n partialOverlapFound = true;\n break;\n }\n }\n const deltaAddCount = hits.filter((el) => !currentSet.has(el)).length;\n const violatesIntersection = !allowIntersectionSelection && (\n partialOverlapFound ||\n (!allowContainmentSelection && containmentFound)\n );\n const violatesUnion = !allowUnionSelection && deltaAddCount > 0; // 禁并集:禁止新增元素\n const invalid = violatesIntersection || violatesUnion;\n\n if (invalid) {\n // 取消本次调整:恢复选择与覆盖层\n const union = new Set<Element>();\n groups.forEach((g) => g.forEach((el) => union.add(el)));\n updateDomSelection(union);\n renderGroupOverlays(); // 覆盖层回到原框\n // 结束会话\n resizeSession = null;\n document.removeEventListener(\"mousemove\", onResizeMove);\n notifySelectionEnd();\n return;\n }\n\n groups[idx] = hits;\n // 按所有组并集更新 DOM\n const union = new Set<Element>();\n groups.forEach((g) => g.forEach((el) => union.add(el)));\n updateDomSelection(union);\n // 重绘覆盖层以贴合元素外框\n renderGroupOverlays();\n // 结束会话\n resizeSession = null;\n document.removeEventListener(\"mousemove\", onResizeMove);\n // 通知一次选区结束\n notifySelectionEnd();\n };\n\n // 内部:按下标移除组\n const removeGroupAt = (index: number): boolean => {\n if (index < 0 || index >= groups.length) return false;\n const arr = groups[index];\n if (arr) arr.forEach((el) => ((el as HTMLElement).style.visibility = \"\"));\n groups.splice(index, 1);\n groupHidden.splice(index, 1);\n groupColors.splice(index, 1);\n if (lastCreatedGroupIndex !== null) {\n if (lastCreatedGroupIndex === index) lastCreatedGroupIndex = null;\n else if (lastCreatedGroupIndex > index) lastCreatedGroupIndex--;\n }\n clearGroupOverlays();\n renderGroupOverlays();\n const union = new Set<Element>();\n groups.forEach((g) => g.forEach((el) => union.add(el)));\n updateDomSelection(union);\n // 通知一次选区结束,用于更新结果面板\n notifySelectionEnd();\n return true;\n };\n\n // 内部:将指定元素集合加入为一个新组(遵循交/并限制与去重规则)\n const addGroupInternal = (elements: Element[]): boolean => {\n if (!groupMode) return false;\n if (!Array.isArray(elements) || elements.length === 0) return false;\n // 归一化:去重 + 过滤不在容器内/被排除/不匹配选择器的元素\n const uniq = Array.from(new Set(elements)).filter((el) => {\n try {\n return (\n !!el &&\n container.contains(el) &&\n !isExcluded(el) &&\n (el as Element).matches?.(selectable)\n );\n } catch {\n return false;\n }\n });\n if (uniq.length === 0) return false;\n\n // 阻止重复编组:与现有某组元素集合完全一致\n const dup = findDuplicateGroupIndex(uniq);\n if (dup !== null) return false;\n\n // 与当前选择并集进行“交/并限制”校验\n // 针对“交/并”限制做精细化:允许包含关系(若 allowContainmentSelection=true)\n const hitsSet = new Set<Element>(uniq);\n let partialOverlapFound = false;\n let containmentFound = false;\n for (const g of groups) {\n const gSet = new Set<Element>(g);\n let interCount = 0;\n for (const el of hitsSet) if (gSet.has(el)) interCount++;\n if (interCount === 0) continue;\n if (interCount === gSet.size && interCount === hitsSet.size) {\n // equal -> 视为重复(已在上方重复检测处理),这里忽略\n continue;\n } else if (interCount === gSet.size || interCount === hitsSet.size) {\n containmentFound = true;\n } else {\n partialOverlapFound = true;\n break;\n }\n }\n const base = new Set<Element>(selectedSet); // 当前整体选中(用于并集限制)\n const violatesIntersection = !allowIntersectionSelection && (\n partialOverlapFound ||\n (!allowContainmentSelection && containmentFound)\n );\n const violatesUnion =\n !allowUnionSelection && base.size > 0 && uniq.length > 0;\n if (violatesIntersection || violatesUnion) return false;\n\n // 正式创建新组\n groups.push(uniq);\n groupHidden.push(false);\n groupColors.push(getNewGroupColor());\n lastCreatedGroupIndex = groups.length - 1;\n // 更新 DOM 选中与覆盖层\n const union = new Set<Element>();\n groups.forEach((g) => g.forEach((el) => union.add(el)));\n updateDomSelection(union);\n renderGroupOverlays();\n notifySelectionEnd();\n return true;\n };\n\n const resolveCombineMode = (\n e: MouseEvent\n ): \"replace\" | \"add\" | \"subtract\" | \"toggle\" => {\n if (groupMode) return \"add\"; // 编组时默认累加\n const fallback = multi ? combineMode ?? \"add\" : \"replace\";\n if (!multi) return \"replace\";\n if (combineMode === \"auto\") {\n if (e.shiftKey) return \"add\";\n if (e.altKey) return \"subtract\";\n if (e.metaKey || e.ctrlKey) return \"toggle\";\n return \"add\";\n }\n return (combineMode as any) ?? fallback;\n };\n\n const updateDomSelection = (next: Set<Element>) => {\n // 移除不再选中的\n for (const el of Array.from(selectedSet)) {\n if (!next.has(el)) (el as Element).classList.remove(selectedClass);\n }\n // 添加新选中的\n for (const el of Array.from(next)) {\n if (!selectedSet.has(el)) (el as Element).classList.add(selectedClass);\n }\n selectedSet = next;\n if (onChange) {\n if (groupMode) {\n onChange({\n type: \"groups\",\n groups: groups.slice(),\n flat: Array.from(selectedSet),\n });\n } else {\n onChange({ type: \"single\", selected: Array.from(selectedSet) });\n }\n }\n };\n\n const combineWith = (\n base: Set<Element>,\n hits: Element[],\n mode: \"replace\" | \"add\" | \"subtract\" | \"toggle\"\n ): Set<Element> => {\n if (mode === \"replace\") return new Set(hits);\n const result = new Set(base);\n if (mode === \"add\") {\n for (const h of hits) result.add(h);\n } else if (mode === \"subtract\") {\n for (const h of hits) result.delete(h);\n } else if (mode === \"toggle\") {\n for (const h of hits) {\n if (result.has(h)) result.delete(h);\n else result.add(h);\n }\n }\n return result;\n };\n\n // 在 document 级别监听,保证拖拽过程中不丢失事件\n const onMouseDown = (e: MouseEvent) => {\n // 仅左键\n if (e.button !== 0) return;\n\n // 限制必须在容器内按下,body可以选\n const target = e.target as Node;\n if (!container.contains(target) && target !== document.body) return;\n\n // 记录起点\n startX = e.clientX;\n startY = e.clientY;\n isDragging = true;\n marqueeEl = createMarquee();\n // 记录多选基线与模式\n dragCombine = resolveCombineMode(e);\n baseSet = new Set(selectedSet);\n e.preventDefault();\n };\n\n const onMouseMove = (e: MouseEvent) => {\n // 悬浮高亮:仅在未拖拽时处理\n if (!isDragging && hoverHighlight) {\n const t = e.target as Element | null;\n const cand = t?.closest?.(selectable) as Element | null;\n if (cand && container.contains(cand) && !isExcluded(cand))\n setHovered(cand);\n else setHovered(null);\n }\n if (!isDragging || !marqueeEl) return;\n const { left, top, width, height } = getCurrentMarqueeRect(\n startX,\n startY,\n e.clientX,\n e.clientY\n );\n marqueeEl.style.left = `${left}px`;\n marqueeEl.style.top = `${top}px`;\n marqueeEl.style.width = `${width}px`;\n marqueeEl.style.height = `${height}px`;\n // 实时高亮(预览合并后的集合)\n const hits = computeSelection(left, top, width, height);\n const base = baseSet ?? new Set<Element>();\n // 规则校验\n const hitsSet = new Set<Element>(hits);\n let interCount = 0;\n for (const el of hitsSet) if (base.has(el)) interCount++;\n let relation: 'disjoint'|'equal'|'containment'|'partial' = 'disjoint';\n if (interCount === 0) relation = 'disjoint';\n else if (interCount === hitsSet.size && interCount === base.size) relation = 'equal';\n else if (interCount === hitsSet.size || interCount === base.size) relation = 'containment';\n else relation = 'partial';\n const violatesIntersection = !allowIntersectionSelection && (\n relation === 'partial' || (!allowContainmentSelection && relation === 'containment')\n );\n const violatesUnion =\n !allowUnionSelection && base.size > 0 && hits.length > 0;\n dragInvalid = violatesIntersection || violatesUnion;\n // 提示红框/蓝框\n if (marqueeEl) {\n if (dragInvalid) {\n marqueeEl.style.outline = \"1px dashed #ff4d4f\";\n marqueeEl.style.background = \"rgba(255,77,79,0.12)\";\n } else {\n marqueeEl.style.outline = \"1px dashed #268aff\";\n marqueeEl.style.background = \"rgba(38,138,255,0.12)\";\n }\n }\n // 预览:无效则保持基线不变,有效才合并预览\n if (dragInvalid) {\n updateDomSelection(base);\n } else {\n const next = combineWith(base, hits, dragCombine);\n updateDomSelection(next);\n }\n };\n\n const onMouseUp = (e: MouseEvent) => {\n if (!isDragging) return;\n isDragging = false;\n if (marqueeEl && marqueeEl.parentNode)\n marqueeEl.parentNode.removeChild(marqueeEl);\n marqueeEl = null;\n\n // 最终一次计算,确保结果准确\n const { left, top, width, height } = getCurrentMarqueeRect(\n startX,\n startY,\n e.clientX,\n e.clientY\n );\n const hits = computeSelection(left, top, width, height);\n const base = baseSet ?? new Set<Element>();\n // 规则校验(与 move 同步)\n const hitsSet = new Set<Element>(hits);\n let interCount = 0;\n for (const el of hitsSet) if (base.has(el)) interCount++;\n let relation: 'disjoint'|'equal'|'containment'|'partial' = 'disjoint';\n if (interCount === 0) relation = 'disjoint';\n else if (interCount === hitsSet.size && interCount === base.size) relation = 'equal';\n else if (interCount === hitsSet.size || interCount === base.size) relation = 'containment';\n else relation = 'partial';\n const violatesIntersection = !allowIntersectionSelection && (\n relation === 'partial' || (!allowContainmentSelection && relation === 'containment')\n );\n const violatesUnion =\n !allowUnionSelection && base.size > 0 && hits.length > 0;\n const invalid = violatesIntersection || violatesUnion;\n if (invalid) {\n // 直接取消本次圈选\n updateDomSelection(base);\n baseSet = null;\n notifySelectionEnd();\n return;\n }\n const next = combineWith(base, hits, dragCombine);\n updateDomSelection(next);\n if (groupMode && hits.length > 0) {\n // 阻止重复编组:与现有某组元素集合完全一致\n const dup = findDuplicateGroupIndex(hits);\n if (dup !== null) {\n try {\n console.warn(`重复编组被阻止:与已存在的第${dup + 1}组元素完全一致`);\n } catch {}\n // 仍然完成一次交互通知(但不创建新组)\n baseSet = null;\n notifySelectionEnd();\n return;\n }\n groups.push(hits);\n lastCreatedGroupIndex = groups.length - 1;\n groupHidden.push(false);\n groupColors.push(getNewGroupColor());\n const union = new Set<Element>();\n groups.forEach((g) => g.forEach((el) => union.add(el)));\n updateDomSelection(union);\n renderGroupOverlays();\n }\n baseSet = null;\n // 通知监听者:一次完整拖拽已结束\n notifySelectionEnd();\n };\n\n // 双击快速成组(以双击元素的外框作为选择框)\n const onDblClick = (e: MouseEvent) => {\n if (!quickGroupOnDblClick || !groupMode) return;\n const target = e.target as Element | null;\n if (!target) return;\n // 限制在容器内\n let node: Element | null = target as Element;\n if (quickGroupSelector) {\n node = (target.closest?.(quickGroupSelector) as Element) || null;\n }\n if (!node || !container.contains(node)) return;\n const r = node.getBoundingClientRect();\n const hits = computeSelection(r.left, r.top, r.width, r.height);\n // 与当前选择的冲突检测\n const base = new Set<Element>(selectedSet);\n const hitsSet = new Set<Element>(hits);\n let interCount = 0;\n for (const el of hitsSet) if (base.has(el)) interCount++;\n let relation: 'disjoint'|'equal'|'containment'|'partial' = 'disjoint';\n if (interCount === 0) relation = 'disjoint';\n else if (interCount === hitsSet.size && interCount === base.size) relation = 'equal';\n else if (interCount === hitsSet.size || interCount === base.size) relation = 'containment';\n else relation = 'partial';\n const violatesIntersection = !allowIntersectionSelection && (\n relation === 'partial' || (!allowContainmentSelection && relation === 'containment')\n );\n const violatesUnion =\n !allowUnionSelection && base.size > 0 && hits.length > 0;\n if (hits.length === 0 || violatesIntersection || violatesUnion) {\n // 无命中也触发一次刷新,确保面板与状态同步(可选择忽略)\n notifySelectionEnd();\n return;\n }\n // 阻止重复编组:与现有某组元素集合完全一致\n const dup = findDuplicateGroupIndex(hits);\n if (dup !== null) {\n try {\n console.warn(`重复编组被阻止:与已存在的第${dup + 1}组元素完全一致`);\n } catch {}\n notifySelectionEnd();\n return;\n }\n groups.push(hits);\n lastCreatedGroupIndex = groups.length - 1;\n groupHidden.push(false);\n groupColors.push(getNewGroupColor());\n const union = new Set<Element>();\n groups.forEach((g) => g.forEach((el) => union.add(el)));\n updateDomSelection(union);\n renderGroupOverlays();\n notifySelectionEnd();\n };\n\n // 容器离开时清除悬浮样式\n const onContainerLeave = () => setHovered(null);\n\n function computeSelection(\n left: number,\n top: number,\n width: number,\n height: number\n ): Element[] {\n // 空框直接返回空\n if (width === 0 || height === 0) return [];\n\n // 限制只计算容器可见区域内元素\n const containerRect = container.getBoundingClientRect();\n const marqueeRect = new DOMRect(left, top, width, height);\n\n // 仅在与容器区域相交时才继续\n if (!rectIntersects(marqueeRect, containerRect)) return [];\n\n const nodes = Array.from(container.querySelectorAll(selectable));\n let selected: Element[] = [];\n const scoreMap = new Map<Element, number>();\n for (const el of nodes) {\n // 跳过排除元素\n if (isExcluded(el)) continue;\n const r = el.getBoundingClientRect();\n // 可选策略:先与容器相交,再与选择框判断\n if (!rectIntersects(r, containerRect)) continue;\n\n let hit = false;\n if (selectionMode === \"contains\") {\n hit = rectContains(marqueeRect, r);\n } else if (selectionMode === \"center\") {\n const cx = r.left + r.width / 2;\n const cy = r.top + r.height / 2;\n hit =\n cx >= marqueeRect.left &&\n cx <= marqueeRect.right &&\n cy >= marqueeRect.top &&\n cy <= marqueeRect.bottom;\n } else {\n // intersects + 面积占比阈值\n if (rectIntersects(marqueeRect, r)) {\n const ratio = getRatio(marqueeRect, r);\n hit = ratio >= Math.max(0, Math.min(1, minOverlapRatio));\n }\n }\n if (hit) {\n const score =\n selectionMode === \"contains\" ? 1 : getRatio(marqueeRect, r);\n scoreMap.set(el, score);\n selected.push(el);\n }\n }\n\n // 冲突处理\n const strategy: \"none\" | \"leaf\" | \"best\" =\n conflictStrategy ?? (preventAncestorSelection ? \"leaf\" : \"none\");\n if (strategy !== \"none\" && selected.length > 1) {\n if (strategy === \"leaf\") {\n // 仅保留叶子命中的元素,避免选中大容器\n selected = selected.filter(\n (el) =>\n !selected.some(\n (other) => other !== el && (el as Node).contains(other)\n )\n );\n } else if (strategy === \"best\") {\n // 在每条祖先链上保留分数更高者\n const byScoreDesc = [...selected].sort(\n (a, b) => (scoreMap.get(b) || 0) - (scoreMap.get(a) || 0)\n );\n const kept: Element[] = [];\n for (const el of byScoreDesc) {\n const conflict = kept.find(\n (k) => (k as Node).contains(el) || (el as Node).contains(k)\n );\n if (!conflict) kept.push(el);\n }\n selected = kept;\n }\n }\n\n return selected;\n }\n\n // 绑定监听\n document.addEventListener(\"mousedown\", onMouseDown, true);\n document.addEventListener(\"mousemove\", onMouseMove);\n document.addEventListener(\"mouseup\", onMouseUp);\n if (hoverHighlight) {\n container.addEventListener(\"mouseleave\", onContainerLeave);\n }\n if (groupMode && quickGroupOnDblClick) {\n container.addEventListener(\"dblclick\", onDblClick);\n }\n // 监听滚动与尺寸变化,刷新组外框位置\n const onScrollOrResize = () => renderGroupOverlays();\n if (groupMode) {\n window.addEventListener(\"scroll\", onScrollOrResize, true);\n window.addEventListener(\"resize\", onScrollOrResize);\n }\n\n // 返回销毁器\n const buildSnapshot = (): MarqueeSelectionSnapshot => {\n if (groupMode) {\n const rects = groups.map((g) => calcGroupRect(g));\n // 计算组级嵌套:根据外接矩形包含关系,找到每个组的最近父组\n const parents: (number | null)[] = Array(groups.length).fill(null);\n const areas = rects.map((r) =>\n r ? Math.max(0, r.width * r.height) : Number.POSITIVE_INFINITY\n );\n for (let i = 0; i < groups.length; i++) {\n const ri = rects[i];\n if (!ri) continue;\n let best: number | null = null;\n let bestArea = Number.POSITIVE_INFINITY;\n for (let j = 0; j < groups.length; j++) {\n if (i === j) continue;\n const rj = rects[j];\n if (!rj) continue;\n const contains =\n rj.left <= ri.left &&\n rj.top <= ri.top &&\n rj.left + rj.width >= ri.left + ri.width &&\n rj.top + rj.height >= ri.top + ri.height;\n if (contains) {\n const area = Number(areas[j]);\n if (area < bestArea) {\n bestArea = area;\n best = j;\n }\n }\n }\n parents[i] = best;\n }\n const children: number[][] = Array.from(\n { length: groups.length },\n () => []\n );\n for (let i = 0; i < groups.length; i++) {\n const p = parents[i];\n if (p !== null && p !== undefined && children[p]) children[p].push(i);\n }\n const roots: number[] = [];\n for (let i = 0; i < groups.length; i++) {\n if (parents[i] === null || parents[i] === undefined) roots.push(i);\n }\n return {\n type: \"groups\",\n groups: groups.map((g) => g.slice()),\n flat: Array.from(selectedSet),\n hidden: groupHidden.slice(),\n groupRects: rects,\n groupNesting: { parents, children, roots },\n };\n }\n return { type: \"single\", selected: Array.from(selectedSet) };\n };\n\n const notifySelectionEnd = () => {\n const snap = buildSnapshot();\n // 先调用可选的 options 回调\n if (onSelectionEndOption) {\n try {\n onSelectionEndOption(snap);\n } catch {}\n }\n for (const fn of endListeners) {\n try {\n fn(snap);\n } catch {}\n }\n const waiters = endWaiters.splice(0);\n for (const resolve of waiters) {\n try {\n resolve(snap);\n } catch {}\n }\n };\n\n const controller: MarqueeSelectionController = {\n destroy() {\n document.removeEventListener(\"mousedown\", onMouseDown);\n document.removeEventListener(\"mousemove\", onMouseMove);\n document.removeEventListener(\"mouseup\", onMouseUp);\n // 清理选择框与样式\n if (marqueeEl && marqueeEl.parentNode)\n marqueeEl.parentNode.removeChild(marqueeEl);\n marqueeEl = null;\n const prev = container.querySelectorAll(`.${selectedClass}`);\n prev.forEach((n) => n.classList.remove(selectedClass));\n if (hoverHighlight) {\n container.removeEventListener(\"mouseleave\", onContainerLeave);\n setHovered(null);\n }\n if (groupMode) {\n window.removeEventListener(\"scroll\", onScrollOrResize, true);\n window.removeEventListener(\"resize\", onScrollOrResize);\n }\n if (groupMode && quickGroupOnDblClick) {\n container.removeEventListener(\"dblclick\", onDblClick);\n }\n clearGroupOverlays();\n // 恢复所有元素可见\n groups.forEach((g) =>\n g.forEach((el) => ((el as HTMLElement).style.visibility = \"\"))\n );\n groups = [];\n groupHidden = [];\n groupColors = [];\n lastCreatedGroupIndex = null;\n selectedSet.clear();\n endListeners.splice(0);\n endWaiters.splice(0);\n },\n getGroups() {\n return groups.slice();\n },\n clearGroups() {\n // 恢复所有元素可见\n groups.forEach((g) =>\n g.forEach((el) => ((el as HTMLElement).style.visibility = \"\"))\n );\n groups = [];\n groupHidden = [];\n groupColors = [];\n lastCreatedGroupIndex = null;\n clearGroupOverlays();\n const empty = new Set<Element>();\n updateDomSelection(empty);\n },\n removeGroup(index: number) {\n return removeGroupAt(index);\n },\n addGroup(elements: Element[]) {\n return addGroupInternal(elements);\n },\n setGroupVisibility(index: number, hidden: boolean) {\n return setGroupHidden(index, hidden);\n },\n toggleGroupVisibility(index: number) {\n if (index < 0 || index >= groups.length) return false;\n groupHidden[index] = !groupHidden[index];\n applyGroupVisibility(index);\n renderGroupOverlays();\n return true;\n },\n getSelectionResult() {\n return buildSnapshot();\n },\n refresh() {\n renderGroupOverlays();\n },\n hideOverlays() {\n clearGroupOverlays();\n },\n showAndRefreshOverlays() {\n renderGroupOverlays();\n },\n // 获取当前组级嵌套信息\n getGroupNesting() {\n const snap = buildSnapshot();\n return snap.type === \"groups\" ? snap.groupNesting : null;\n },\n onSelectionEnd(handler: (snapshot: MarqueeSelectionSnapshot) => void) {\n endListeners.push(handler);\n return () => {\n const i = endListeners.indexOf(handler);\n if (i >= 0) endListeners.splice(i, 1);\n };\n },\n waitForSelectionEnd() {\n return new Promise<MarqueeSelectionSnapshot>((resolve) => {\n endWaiters.push(resolve);\n });\n },\n };\n controllerRef = controller;\n return controller;\n}\n\nexport default marqueeSelection;\n"],"names":["marqueeSelection","options","container","selectable","exclude","selectionMode","minOverlapRatio","overlapMetric","selectedClass","onChange","preventAncestorSelection","conflictStrategy","groupMode","groupOverlayClass","groupColor","groupRandomColor","groupColorPalette","multi","combineMode","hoverHighlight","hoverClass","onSelectionEndOption","quickGroupOnDblClick","quickGroupSelector","allowIntersectionSelection","allowUnionSelection","allowContainmentSelection","toolbarButtons","excludeSelectors","isExcluded","el","sel","startX","startY","isDragging","marqueeEl","dragInvalid","selectedSet","baseSet","dragCombine","groups","groupOverlays","groupHidden","groupColors","pickPastel","getNewGroupColor","idx","lastCreatedGroupIndex","endListeners","endWaiters","resizeSession","findDuplicateGroupIndex","els","target","i","g","same","gs","controllerRef","applyGroupVisibility","index","hidden","setGroupHidden","hoveredEl","setHovered","createMarquee","rectIntersects","a","b","rectContains","outer","inner","overlapRatio","left","right","top","bottom","w","h","overlap","areaB","iouRatio","inter","areaA","union","getRatio","marqueeRect","elementRect","getCurrentMarqueeRect","x1","y1","x2","y2","width","height","calcGroupRect","rects","r","clearGroupOverlays","renderGroupOverlays","placedToolbarRects","rectsOverlap","box","color","toolbar","label","toggleBtn","ev","notifySelectionEnd","removeBtn","removeGroupAt","getIntersectingIndices","selfIdx","selfRect","list","og","j","ob","orect","ints","mergeBtn","openPanel","old","panel","title","listWrap","checkboxRefs","row","cb","txt","actions","ok","cancel","chosen","c","n","ci","sorted","newIdx","ri","unionSel","updateDomSelection","addCustomButton","cfg","btn","_a","buildSnapshot","anchors","prevVisibility","step","margin","k","rect","collide","pr","ov","addHandle","side","thickness","onResizeMove","onResizeEnd","e","startRect","overlay","dx","dy","minSize","hits","computeSelection","currentSet","otherSet","hitsSet","partialOverlapFound","containmentFound","gSet","interCount","deltaAddCount","violatesIntersection","violatesUnion","arr","addGroupInternal","elements","uniq","base","resolveCombineMode","fallback","next","combineWith","mode","result","onMouseDown","onMouseMove","t","cand","relation","onMouseUp","dup","onDblClick","node","onContainerLeave","containerRect","nodes","selected","scoreMap","hit","cx","cy","score","strategy","other","byScoreDesc","kept","onScrollOrResize","parents","areas","best","bestArea","rj","area","children","p","roots","snap","fn","waiters","resolve","controller","handler"],"mappings":"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"}
|