Navigator
This commit is contained in:
parent
533d2e5cac
commit
6d3bf694c1
@ -18,7 +18,6 @@
|
||||
"katex": "^0.16.9",
|
||||
"simple-mind-map-plugin-themes": "^1.0.0",
|
||||
"@toast-ui/editor": "^3.1.5",
|
||||
"axios": "^1.7.9",
|
||||
"codemirror": "^5.65.16"
|
||||
},
|
||||
"main": "src/index.ts",
|
||||
|
||||
@ -1,10 +0,0 @@
|
||||
import tailwindConfig from './tailwind.config';
|
||||
|
||||
export default {
|
||||
plugins: {
|
||||
...(process.env.NODE_ENV === 'production' ? { cssnano: {} } : {}),
|
||||
autoprefixer: {},
|
||||
tailwindcss: { config: tailwindConfig },
|
||||
'tailwindcss/nesting': {},
|
||||
},
|
||||
};
|
||||
299
web3/packages/mind-map/src/components/Navigator.vue
Normal file
299
web3/packages/mind-map/src/components/Navigator.vue
Normal file
@ -0,0 +1,299 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="showMiniMap"
|
||||
class="navigatorBox"
|
||||
:class="{ isDark: isDark }"
|
||||
ref="navigatorBoxRef"
|
||||
:style="{ width: width + 'px' }"
|
||||
@mousedown="onMousedown"
|
||||
@mousemove="onMousemove"
|
||||
>
|
||||
<div
|
||||
class="svgBox"
|
||||
ref="svgBoxRef"
|
||||
:style="{
|
||||
transform: `scale(${svgBoxScale})`,
|
||||
left: svgBoxLeft + 'px',
|
||||
top: svgBoxTop + 'px',
|
||||
}"
|
||||
>
|
||||
<img :src="mindMapImg" @mousedown.prevent />
|
||||
</div>
|
||||
<div
|
||||
class="windowBox"
|
||||
:style="viewBoxStyle"
|
||||
:class="{ withTransition: withTransition }"
|
||||
@mousedown.stop="onViewBoxMousedown"
|
||||
@mousemove="onViewBoxMousemove"
|
||||
></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted, computed, nextTick, watch } from "vue";
|
||||
import { useMindMapStore } from "../index";
|
||||
|
||||
import { storeToRefs } from "pinia";
|
||||
|
||||
const { getMindMapInstance } = useMindMapStore();
|
||||
const { isDark, showMiniMap } = storeToRefs(useMindMapStore());
|
||||
|
||||
const timer = ref(null);
|
||||
|
||||
const boxWidth = ref(0);
|
||||
const boxHeight = ref(0);
|
||||
const svgBoxScale = ref(1);
|
||||
const svgBoxLeft = ref(0);
|
||||
const svgBoxTop = ref(0);
|
||||
|
||||
const viewBoxStyle = ref({
|
||||
left: "0px", // 确保初始值为字符串以匹配后续更新
|
||||
top: "0px",
|
||||
bottom: "0px",
|
||||
right: "0px",
|
||||
});
|
||||
|
||||
const mindMapImg = ref("");
|
||||
|
||||
const width = ref(0);
|
||||
const setSizeTimer = ref(null);
|
||||
const withTransition = ref(true);
|
||||
|
||||
const navigatorBoxRef = ref(null);
|
||||
const svgBoxRef = ref(null);
|
||||
|
||||
function init() {
|
||||
if (!navigatorBoxRef.value) return;
|
||||
const rect = navigatorBoxRef.value.getBoundingClientRect();
|
||||
boxWidth.value = rect.width;
|
||||
boxHeight.value = rect.height;
|
||||
}
|
||||
|
||||
function drawMiniMap() {
|
||||
const currentMindMap = getMindMapInstance();
|
||||
if (
|
||||
!currentMindMap ||
|
||||
!currentMindMap.miniMap ||
|
||||
!boxWidth.value ||
|
||||
!boxHeight.value
|
||||
)
|
||||
return;
|
||||
try {
|
||||
const calculationResult = currentMindMap.miniMap.calculationMiniMap(
|
||||
boxWidth.value,
|
||||
boxHeight.value
|
||||
);
|
||||
if (!calculationResult) return;
|
||||
|
||||
const {
|
||||
getImgUrl,
|
||||
viewBoxStyle: newViewBoxStyle,
|
||||
miniMapBoxScale: newMiniMapBoxScale,
|
||||
miniMapBoxLeft: newMiniMapBoxLeft,
|
||||
miniMapBoxTop: newMiniMapBoxTop,
|
||||
} = calculationResult;
|
||||
|
||||
if (getImgUrl && typeof getImgUrl === "function") {
|
||||
getImgUrl((img) => {
|
||||
mindMapImg.value = img;
|
||||
});
|
||||
}
|
||||
if (newViewBoxStyle) viewBoxStyle.value = newViewBoxStyle;
|
||||
if (newMiniMapBoxScale !== undefined)
|
||||
svgBoxScale.value = newMiniMapBoxScale;
|
||||
if (newMiniMapBoxLeft !== undefined) svgBoxLeft.value = newMiniMapBoxLeft;
|
||||
if (newMiniMapBoxTop !== undefined) svgBoxTop.value = newMiniMapBoxTop;
|
||||
} catch (error) {
|
||||
console.error("Error drawing minimap:", error);
|
||||
}
|
||||
}
|
||||
|
||||
function toggle_mini_map(show) {
|
||||
showMiniMap.value = show; // 更新 store 中的状态
|
||||
// nextTick 逻辑移至 watch
|
||||
}
|
||||
|
||||
watch(
|
||||
() => showMiniMap.value,
|
||||
(isShown) => {
|
||||
if (isShown) {
|
||||
nextTick(() => {
|
||||
navigatorBoxRef.value && init();
|
||||
svgBoxRef.value && drawMiniMap();
|
||||
});
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
function data_change() {
|
||||
if (!showMiniMap.value) {
|
||||
// 使用 store 中的状态
|
||||
return;
|
||||
}
|
||||
clearTimeout(timer.value);
|
||||
timer.value = setTimeout(() => {
|
||||
drawMiniMap();
|
||||
}, 500);
|
||||
}
|
||||
|
||||
function setSize() {
|
||||
clearTimeout(setSizeTimer.value);
|
||||
setSizeTimer.value = setTimeout(() => {
|
||||
width.value = Math.min(window.innerWidth - 80, 370);
|
||||
nextTick(() => {
|
||||
if (showMiniMap.value && navigatorBoxRef.value) {
|
||||
init();
|
||||
drawMiniMap();
|
||||
}
|
||||
});
|
||||
}, 300);
|
||||
}
|
||||
|
||||
function onMousedown(e) {
|
||||
const currentMindMap = getMindMapInstance();
|
||||
if (
|
||||
currentMindMap &&
|
||||
currentMindMap.miniMap &&
|
||||
typeof currentMindMap.miniMap.onMousedown === "function"
|
||||
) {
|
||||
currentMindMap.miniMap.onMousedown(e);
|
||||
}
|
||||
}
|
||||
|
||||
function onMousemove(e) {
|
||||
const currentMindMap = getMindMapInstance();
|
||||
if (
|
||||
currentMindMap &&
|
||||
currentMindMap.miniMap &&
|
||||
typeof currentMindMap.miniMap.onMousemove === "function"
|
||||
) {
|
||||
currentMindMap.miniMap.onMousemove(e);
|
||||
}
|
||||
}
|
||||
|
||||
function onMouseup(e) {
|
||||
if (!withTransition.value) {
|
||||
withTransition.value = true;
|
||||
}
|
||||
const currentMindMap = getMindMapInstance();
|
||||
if (
|
||||
currentMindMap &&
|
||||
currentMindMap.miniMap &&
|
||||
typeof currentMindMap.miniMap.onMouseup === "function"
|
||||
) {
|
||||
currentMindMap.miniMap.onMouseup(e);
|
||||
}
|
||||
}
|
||||
|
||||
function onViewBoxMousedown(e) {
|
||||
const currentMindMap = getMindMapInstance();
|
||||
if (
|
||||
currentMindMap &&
|
||||
currentMindMap.miniMap &&
|
||||
typeof currentMindMap.miniMap.onViewBoxMousedown === "function"
|
||||
) {
|
||||
currentMindMap.miniMap.onViewBoxMousedown(e);
|
||||
}
|
||||
}
|
||||
|
||||
function onViewBoxMousemove(e) {
|
||||
const currentMindMap = getMindMapInstance();
|
||||
if (
|
||||
currentMindMap &&
|
||||
currentMindMap.miniMap &&
|
||||
typeof currentMindMap.miniMap.onViewBoxMousemove === "function"
|
||||
) {
|
||||
currentMindMap.miniMap.onViewBoxMousemove(e);
|
||||
}
|
||||
}
|
||||
|
||||
function onViewBoxPositionChange({ left, right, top, bottom }) {
|
||||
withTransition.value = false;
|
||||
viewBoxStyle.value.left = left;
|
||||
viewBoxStyle.value.right = right;
|
||||
viewBoxStyle.value.top = top;
|
||||
viewBoxStyle.value.bottom = bottom;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
setSize();
|
||||
window.addEventListener("resize", setSize);
|
||||
window.addEventListener("mouseup", onMouseup);
|
||||
|
||||
// 事件总线监听 (请根据您的项目调整)
|
||||
// eventBus.on('toggle_mini_map', toggle_mini_map);
|
||||
// eventBus.on('data_change', data_change);
|
||||
// eventBus.on('view_data_change', data_change); // Vue2 中 view_data_change 和 data_change 调用相同处理函数
|
||||
// eventBus.on('node_tree_render_end', data_change);
|
||||
|
||||
// watch(getMindMapInstance(), (newInstance) => {
|
||||
// if (newInstance && typeof newInstance.on === 'function') {
|
||||
// newInstance.on(
|
||||
// 'mini_map_view_box_position_change',
|
||||
// onViewBoxPositionChange
|
||||
// );
|
||||
// }
|
||||
// }, { immediate: true });
|
||||
|
||||
// 如果初始时就需要显示小地图,可以在这里调用 toggle_mini_map(true)
|
||||
// 或者通过外部事件触发
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener("resize", setSize);
|
||||
window.removeEventListener("mouseup", onMouseup);
|
||||
|
||||
// 事件总线解绑 (请根据您的项目调整)
|
||||
// eventBus.off('toggle_mini_map', toggle_mini_map);
|
||||
// eventBus.off('data_change', data_change);
|
||||
// eventBus.off('view_data_change', data_change);
|
||||
// eventBus.off('node_tree_render_end', data_change);
|
||||
|
||||
const currentMindMap = getMindMapInstance();
|
||||
if (currentMindMap && typeof currentMindMap.off === "function") {
|
||||
currentMindMap.off(
|
||||
"mini_map_view_box_position_change",
|
||||
onViewBoxPositionChange
|
||||
);
|
||||
}
|
||||
clearTimeout(timer.value);
|
||||
clearTimeout(setSizeTimer.value);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.navigatorBox {
|
||||
position: absolute;
|
||||
height: 220px;
|
||||
background-color: #fff;
|
||||
bottom: 24px;
|
||||
right: 24px;
|
||||
box-shadow: 0 0 16px #989898;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #eee;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
|
||||
&.isDark {
|
||||
background-color: #262a2e;
|
||||
}
|
||||
|
||||
.svgBox {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
transform-origin: left top;
|
||||
}
|
||||
|
||||
.windowBox {
|
||||
position: absolute;
|
||||
border: 2px solid rgb(238, 69, 69);
|
||||
background-color: rgba(238, 69, 69, 0.2);
|
||||
|
||||
&.withTransition {
|
||||
transition: all 0.3s;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -7,11 +7,13 @@ import ExportPDF from 'simple-mind-map/src/plugins/ExportPDF'
|
||||
import ExportXMind from 'simple-mind-map/src/plugins/ExportXMind'
|
||||
import Export from 'simple-mind-map/src/plugins/Export'
|
||||
import MindMapLayoutPro from 'simple-mind-map/src/plugins/MindMapLayoutPro'
|
||||
import MiniMap from 'simple-mind-map/src/plugins/MiniMap'
|
||||
// import RichText from 'simple-mind-map/src/plugins/RichText'
|
||||
|
||||
|
||||
export function usePlugins(MindMapConstructor: typeof MindMap) {
|
||||
// 注册插件
|
||||
MindMapConstructor.usePlugin(MiniMap);
|
||||
MindMapConstructor.usePlugin(ExportPDF);
|
||||
MindMapConstructor.usePlugin(ExportXMind);
|
||||
MindMapConstructor.usePlugin(Export);
|
||||
|
||||
@ -39,6 +39,12 @@ function defineStoreImplementation() {
|
||||
|
||||
const mindMapData = ref(null);
|
||||
|
||||
// 是否小地图
|
||||
const showMiniMap = ref(true);
|
||||
|
||||
// 是否深色
|
||||
const isDark = ref(false);
|
||||
|
||||
// 激活状态节点
|
||||
const activeNodes = shallowRef<MindMapNode[]>([]);
|
||||
|
||||
@ -136,6 +142,8 @@ function defineStoreImplementation() {
|
||||
mindMapData,
|
||||
activeNodes,
|
||||
currentLayout,
|
||||
showMiniMap,
|
||||
isDark,
|
||||
|
||||
getMindMapInstance,
|
||||
importFile,
|
||||
|
||||
4
web3/packages/mind-map/src/types/index.d.ts
vendored
4
web3/packages/mind-map/src/types/index.d.ts
vendored
@ -35,4 +35,8 @@ declare module 'simple-mind-map/src/plugins/RichText' {
|
||||
import RichText from 'simple-mind-map/types/src/plugins/RichText';
|
||||
export default RichText;
|
||||
}
|
||||
declare module 'simple-mind-map/src/plugins/MiniMap' {
|
||||
import MiniMap from 'simple-mind-map/types/src/plugins/MiniMap';
|
||||
export default MiniMap;
|
||||
}
|
||||
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
<div class="relative w-full h-full border">
|
||||
<!-- 操作拦 -->
|
||||
<ToolBar />
|
||||
<!-- 导航器 -->
|
||||
<Navigator />
|
||||
<div
|
||||
class="w-full h-full mindMapContainer"
|
||||
id="mindMapContainer"
|
||||
@ -13,6 +15,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref } from "vue";
|
||||
import ToolBar from "../components/ToolBar.vue";
|
||||
import Navigator from "../components/Navigator.vue";
|
||||
|
||||
import { useMindMapStore } from "../store/index";
|
||||
import type MindMapNode from "simple-mind-map/types/src/core/render/node/MindMapNode";
|
||||
|
||||
@ -1,50 +0,0 @@
|
||||
import type { Config } from 'tailwindcss'
|
||||
|
||||
export default {
|
||||
content: [
|
||||
"./index.html",
|
||||
"./src/**/*.{vue,js,ts,jsx,tsx,mdx}",
|
||||
],
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
border: "rgb(var(--border) / <alpha-value>)",
|
||||
input: "rgb(var(--input) / <alpha-value>)",
|
||||
ring: "rgb(var(--ring) / <alpha-value>)",
|
||||
background: "rgb(var(--background) / <alpha-value>)",
|
||||
foreground: "rgb(var(--foreground) / <alpha-value>)",
|
||||
primary: {
|
||||
DEFAULT: "rgb(var(--primary) / <alpha-value>)",
|
||||
foreground: "rgb(var(--primary-foreground) / <alpha-value>)",
|
||||
hover: "rgb(var(--primary-hover) / <alpha-value>)",
|
||||
active: "rgb(var(--primary-active) / <alpha-value>)",
|
||||
},
|
||||
secondary: {
|
||||
DEFAULT: "rgb(var(--secondary) / <alpha-value>)",
|
||||
foreground: "rgb(var(--secondary-foreground) / <alpha-value>)",
|
||||
},
|
||||
destructive: {
|
||||
DEFAULT: "rgb(var(--destructive) / <alpha-value>)",
|
||||
foreground: "rgb(var(--destructive-foreground) / <alpha-value>)",
|
||||
},
|
||||
muted: {
|
||||
DEFAULT: "rgb(var(--muted) / <alpha-value>)",
|
||||
foreground: "rgb(var(--muted-foreground) / <alpha-value>)",
|
||||
},
|
||||
accent: {
|
||||
DEFAULT: "rgb(var(--accent) / <alpha-value>)",
|
||||
foreground: "rgb(var(--accent-foreground) / <alpha-value>)",
|
||||
},
|
||||
popover: {
|
||||
DEFAULT: "rgb(var(--popover) / <alpha-value>)",
|
||||
foreground: "rgb(var(--popover-foreground) / <alpha-value>)",
|
||||
},
|
||||
card: {
|
||||
DEFAULT: "rgb(var(--card) / <alpha-value>)",
|
||||
foreground: "rgb(var(--card-foreground) / <alpha-value>)",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
} satisfies Config
|
||||
0
web3/packages/mind-map/vite.config.ts
Normal file
0
web3/packages/mind-map/vite.config.ts
Normal file
Loading…
x
Reference in New Issue
Block a user