|
@@ -0,0 +1,194 @@
|
|
|
+import { Cell, Graph } from "@antv/x6"
|
|
|
+import { useEffect, useState } from "react"
|
|
|
+
|
|
|
+export const useFindReplace = (graph?: Graph) => {
|
|
|
+
|
|
|
+ const [graphInstance, setGraphInstance] = useState<Graph | undefined>(graph);
|
|
|
+ // 总的匹配数
|
|
|
+ const [count, setCount] = useState(0);
|
|
|
+ // 当前匹配的索引
|
|
|
+ const [current, setCurrent] = useState(0);
|
|
|
+ // 匹配集合
|
|
|
+ const [matches, setMatches] = useState<{cell: Cell, count: number}[]>([])
|
|
|
+ const [searchText, setSearchText] = useState('');
|
|
|
+ const setInstance = (graph: Graph) => {
|
|
|
+ setGraphInstance(graph)
|
|
|
+ }
|
|
|
+
|
|
|
+ // TODO 数据变化监听
|
|
|
+ // useEffect(() => {
|
|
|
+ // graph && graph.on("node:change:data", () => {
|
|
|
+ // handleFind(searchText);
|
|
|
+ // })
|
|
|
+ // }, [graph])
|
|
|
+
|
|
|
+ const handleFind = (str: string) => {
|
|
|
+ setSearchText(str);
|
|
|
+ // 查找元素中匹配的文本
|
|
|
+ let count = 0;
|
|
|
+ let cellList: {cell: Cell, count: number}[] = [];
|
|
|
+ const cells = graphInstance?.getCells();
|
|
|
+ (cells || []).forEach(cell => {
|
|
|
+ if(cell.isNode()) {
|
|
|
+ const label = cell.data?.label || '';
|
|
|
+ const regex = new RegExp(str, 'g');
|
|
|
+ const matches = label.match(regex);
|
|
|
+ count += matches ? matches.length : 0;
|
|
|
+ if(matches && matches.length) {
|
|
|
+ cellList.push({
|
|
|
+ cell,
|
|
|
+ count: matches.length
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(cell.isEdge()) {
|
|
|
+ const labels = cell.labels || [];
|
|
|
+ let count = 0;
|
|
|
+ labels.forEach(label => {
|
|
|
+ const regex = new RegExp(str, 'g');
|
|
|
+ const matches = label.text.match(regex);
|
|
|
+ count += matches ? matches.length : 0;
|
|
|
+ if(matches && matches.length) {
|
|
|
+ count = matches.length;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ if(count) {
|
|
|
+ cellList.push({
|
|
|
+ cell,
|
|
|
+ count
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ setCount(count);
|
|
|
+ setCurrent(1);
|
|
|
+ setMatches(cellList);
|
|
|
+ // 通知元素匹配开始
|
|
|
+ cellList.forEach((item, index) => {
|
|
|
+ item.cell.prop("find", {
|
|
|
+ findStr: str,
|
|
|
+ currentCellId: index === 0 ? item.cell.id : undefined,
|
|
|
+ currentIndex: 1,
|
|
|
+ time: new Date().getTime()
|
|
|
+ });
|
|
|
+ })
|
|
|
+ }
|
|
|
+ const handleReplace = (searchText: string, replaceText: string) => {
|
|
|
+ let flag = 0;
|
|
|
+ let flagIndex = 0;
|
|
|
+ let currentCellId: string | undefined;
|
|
|
+ // 找到所在的元素id
|
|
|
+ matches.forEach(item => {
|
|
|
+ if(current > flag && current <= flag + item.count) {
|
|
|
+ currentCellId = item.cell.id;
|
|
|
+ flagIndex = current - flag;
|
|
|
+ }
|
|
|
+ flag += item.count;
|
|
|
+ })
|
|
|
+ matches.forEach((item) => {
|
|
|
+ item.cell.prop("replace", {
|
|
|
+ currentCellId,
|
|
|
+ currentIndex: flagIndex,
|
|
|
+ type: 'replace',
|
|
|
+ searchText,
|
|
|
+ replaceText,
|
|
|
+ time: new Date().getTime()
|
|
|
+ });
|
|
|
+ })
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 全部替换
|
|
|
+ */
|
|
|
+ const handleReplaceAll = (searchText: string, replaceText: string) => {
|
|
|
+ console.log('替换全部:', searchText, replaceText)
|
|
|
+ if(searchText && replaceText) {
|
|
|
+ matches.forEach(item => {
|
|
|
+ item.cell.prop("replace", {
|
|
|
+ type: 'replaceAll',
|
|
|
+ searchText,
|
|
|
+ replaceText,
|
|
|
+ time: new Date().getTime()
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 关闭
|
|
|
+ */
|
|
|
+ const handleClose = () => {
|
|
|
+ matches.forEach((item) => {
|
|
|
+ item.cell.prop("clearFind", {
|
|
|
+ time: new Date().getTime()
|
|
|
+ });
|
|
|
+ });
|
|
|
+ setCount(0);
|
|
|
+ setCurrent(0);
|
|
|
+ setMatches([]);
|
|
|
+ setSearchText('');
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 下一个
|
|
|
+ */
|
|
|
+ const handleFindNext = () => {
|
|
|
+ const currentIndex = current < count ? current + 1 : 1;
|
|
|
+ setCurrent(currentIndex);
|
|
|
+ let flag = 0;
|
|
|
+ let flagIndex = 0;
|
|
|
+ let currentCellId: string | undefined;
|
|
|
+ // 找到所在的元素id
|
|
|
+ matches.forEach(item => {
|
|
|
+ if(currentIndex > flag && currentIndex <= flag + item.count) {
|
|
|
+ currentCellId = item.cell.id;
|
|
|
+ flagIndex = currentIndex - flag;
|
|
|
+ }
|
|
|
+ flag += item.count;
|
|
|
+ })
|
|
|
+ // 计算所在段的索引位置
|
|
|
+ matches.forEach((item) => {
|
|
|
+ item.cell.prop("find", {
|
|
|
+ findStr: searchText,
|
|
|
+ currentCellId,
|
|
|
+ currentIndex: flagIndex,
|
|
|
+ });
|
|
|
+ })
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 上一个
|
|
|
+ */
|
|
|
+ const handleFindPrev = () => {
|
|
|
+ const currentIndex = current > 1 ? current - 1 : count;
|
|
|
+ setCurrent(currentIndex);
|
|
|
+ let flag = 0;
|
|
|
+ let flagIndex = 0;
|
|
|
+ let currentCellId: string | undefined;
|
|
|
+ // 找到所在的元素id
|
|
|
+ matches.forEach(item => {
|
|
|
+ if(currentIndex > flag && currentIndex <= flag + item.count) {
|
|
|
+ currentCellId = item.cell.id;
|
|
|
+ flagIndex = currentIndex - flag;
|
|
|
+ }
|
|
|
+ flag += item.count;
|
|
|
+ })
|
|
|
+ // 计算所在段的索引位置
|
|
|
+ matches.forEach((item, index) => {
|
|
|
+ item.cell.prop("find", {
|
|
|
+ findStr: searchText,
|
|
|
+ currentCellId,
|
|
|
+ currentIndex: flagIndex,
|
|
|
+ });
|
|
|
+ flag = item.count;
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ return {
|
|
|
+ findCount:count,
|
|
|
+ currentIndex: current,
|
|
|
+ setInstance,
|
|
|
+ handleFind,
|
|
|
+ handleReplace,
|
|
|
+ handleReplaceAll,
|
|
|
+ handleClose,
|
|
|
+ handleFindNext,
|
|
|
+ handleFindPrev,
|
|
|
+ }
|
|
|
+}
|