| | |
| | | <h3 class="m-0 px-7 shrink-0 flex items-center justify-between"> |
| | | <span>思维导图预览</span> |
| | | <!-- 展示在右上角 --> |
| | | <el-button type="primary" v-show="isEnd" @click="downloadImage" size="small"> |
| | | <el-button v-show="isEnd" size="small" type="primary" @click="downloadImage"> |
| | | <template #icon> |
| | | <Icon icon="ph:copy-bold" /> |
| | | </template> |
| | |
| | | <div class="flex flex-col items-center justify-center" v-html="html"></div> |
| | | </div> |
| | | |
| | | <div ref="mindmapRef" class="wh-full"> |
| | | <svg ref="svgRef" class="w-full" :style="{ height: `${contentAreaHeight}px` }" /> |
| | | <div ref="mindMapRef" class="wh-full"> |
| | | <svg ref="svgRef" :style="{ height: `${contentAreaHeight}px` }" class="w-full" /> |
| | | <div ref="toolBarRef" class="absolute bottom-[10px] right-5"></div> |
| | | </div> |
| | | </div> |
| | | </el-card> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | <script lang="ts" setup> |
| | | import { Markmap } from 'markmap-view' |
| | | import { Transformer } from 'markmap-lib' |
| | | import { Toolbar } from 'markmap-toolbar' |
| | | import markdownit from 'markdown-it' |
| | | import download from '@/utils/download' |
| | | |
| | | const md = markdownit() |
| | | const message = useMessage() // 消息弹窗 |
| | | |
| | | // TODO @hhero:mindmap 改成 mindMap 更精准哈 |
| | | const props = defineProps<{ |
| | | mindmapResult: string // 生成结果 TODO @hhero 改成 generatedContent 会不会好点 |
| | | generatedContent: string // 生成结果 |
| | | isEnd: boolean // 是否结束 |
| | | isGenerating: boolean // 是否正在生成 |
| | | isStart: boolean // 开始状态,开始时需要清除 html |
| | | }>() |
| | | const contentRef = ref<HTMLDivElement>() // 右侧出来header以下的区域 |
| | | const contentRef = ref<HTMLDivElement>() // 右侧出来 header 以下的区域 |
| | | const mdContainerRef = ref<HTMLDivElement>() // markdown 的容器,用来滚动到底下的 |
| | | const mindmapRef = ref<HTMLDivElement>() // 思维导图的容器 |
| | | const mindMapRef = ref<HTMLDivElement>() // 思维导图的容器 |
| | | const svgRef = ref<SVGElement>() // 思维导图的渲染 svg |
| | | const toolBarRef = ref<HTMLDivElement>() // 思维导图右下角的工具栏,缩放等 |
| | | const html = ref('') // 生成过程中的文本 |
| | |
| | | } |
| | | }) |
| | | |
| | | watch(props, ({ mindmapResult, isGenerating, isEnd, isStart }) => { |
| | | watch(props, ({ generatedContent, isGenerating, isEnd, isStart }) => { |
| | | // 开始生成的时候清空一下 markdown 的内容 |
| | | if (isStart) { |
| | | html.value = '' |
| | | } |
| | | // 生成内容的时候使用 markdown 来渲染 |
| | | if (isGenerating) { |
| | | html.value = md.render(mindmapResult) |
| | | html.value = md.render(generatedContent) |
| | | } |
| | | // 生成结束时更新思维导图 |
| | | if (isEnd) { |
| | | update() |
| | | } |
| | |
| | | /** 更新思维导图的展示 */ |
| | | const update = () => { |
| | | try { |
| | | const { root } = transformer.transform(processContent(props.mindmapResult)) |
| | | const { root } = transformer.transform(processContent(props.generatedContent)) |
| | | markMap?.setData(root) |
| | | markMap?.fit() |
| | | } catch (e) { |
| | |
| | | return arr.join('\n') |
| | | } |
| | | |
| | | /** 下载图片 */ |
| | | // TODO @hhhero:可以抽到 download 这个里面,src/utils/download.ts 么?复用 image 方法? |
| | | // download SVG to png file |
| | | /** 下载图片:download SVG to png file */ |
| | | const downloadImage = () => { |
| | | const svgElement = mindmapRef.value |
| | | const svgElement = mindMapRef.value |
| | | // 将 SVG 渲染到图片对象 |
| | | const serializer = new XMLSerializer() |
| | | const source = |
| | | '<?xml version="1.0" standalone="no"?>\r\n' + serializer.serializeToString(svgRef.value!) |
| | | const image = new Image() |
| | | image.src = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(source) |
| | | |
| | | // 将图片对象渲染 |
| | | const canvas = document.createElement('canvas') |
| | | canvas.width = svgElement?.offsetWidth || 0 |
| | | canvas.height = svgElement?.offsetHeight || 0 |
| | | let context = canvas.getContext('2d') |
| | | context?.clearRect(0, 0, canvas.width, canvas.height) |
| | | |
| | | image.onload = function () { |
| | | context?.drawImage(image, 0, 0) |
| | | const a = document.createElement('a') |
| | | a.download = 'mindmap.png' |
| | | a.href = canvas.toDataURL(`image/png`) |
| | | a.click() |
| | | } |
| | | const source = `<?xml version="1.0" standalone="no"?>\r\n${serializer.serializeToString(svgRef.value!)}` |
| | | const base64Url = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(source)}` |
| | | download.image({ |
| | | url: base64Url, |
| | | canvasWidth: svgElement?.offsetWidth, |
| | | canvasHeight: svgElement?.offsetHeight, |
| | | drawWithImageSize: false |
| | | }) |
| | | } |
| | | |
| | | defineExpose({ |
| | |
| | | height: 0; |
| | | } |
| | | } |
| | | |
| | | .my-card { |
| | | display: flex; |
| | | flex-direction: column; |
| | |
| | | @extend .hide-scroll-bar; |
| | | } |
| | | } |
| | | |
| | | // markmap的tool样式覆盖 |
| | | :deep(.markmap) { |
| | | width: 100%; |
| | | } |
| | | |
| | | :deep(.mm-toolbar-brand) { |
| | | display: none; |
| | | } |
| | | |
| | | :deep(.mm-toolbar) { |
| | | display: flex; |
| | | flex-direction: row; |