diff --git a/1.png b/1.png index fb42dc8a..d06bb5b4 100644 Binary files a/1.png and b/1.png differ diff --git a/5.gif b/4.gif similarity index 100% rename from 5.gif rename to 4.gif diff --git a/4.png b/4.png deleted file mode 100644 index c16c77bc..00000000 Binary files a/4.png and /dev/null differ diff --git a/6.png b/6.png deleted file mode 100644 index 06a65fbc..00000000 Binary files a/6.png and /dev/null differ diff --git a/README.md b/README.md index deb3fa8a..93d5665e 100644 --- a/README.md +++ b/README.md @@ -76,19 +76,20 @@ + 列表自动补全 + 粘贴剪切板里面的图片 + 添加附件到文档 -+ 运行 PHP,nodejs,Python,bash 代码,代码块第一行需要包含以 `--run--` 字符串,示例见下面截图,当然需要安装相关环境 ++ 运行 PHP,nodejs,Python,bash 代码,**代码块第一行需要包含以 `--run--` 字符串,示例见下面截图,当然需要安装相关环境** + 开启了 HTML 解析,可以直接在文档里面使用 HTML 代码 + 待办进度条 + 快速跳转文件,全文搜索文件内容 + 多仓库切换 + 生成 TOC 在需要生成目录的地方写入 `[toc]{type: "ol", level: [1,2,3]}` 即可 -+ docx 格式导出,需要安装 [pandoc](https://pandoc.org/) ++ docx 格式导出,**需要安装 [pandoc](https://pandoc.org/)** ++ ECharts 图形支持装 [ECharts](https://echarts.baidu.com/) **Js代码块第一行需要包含以 `--echarts--` 字符串,示例见下面截图** + markdown 编辑器 [monaco-editor](https://github.com/Microsoft/monaco-editor) + markdown 解析 [markdown-it](https://github.com/markdown-it/markdown-it) + GitHub 风格样式和特性 [GitHub Flavored Markdown Spec](https://github.github.com/gfm/) + 待办列表 [GitHub-style task lists](https://github.com/revin/markdown-it-task-lists) + mermaid 图形 [mermaid](https://github.com/knsv/mermaid) -+ Plantuml 图形,需要安装 Java,graphviz [markdown-it-plantuml](https://github.com/gmunguia/markdown-it-plantuml) ++ Plantuml 图形,**需要安装 Java,graphviz [markdown-it-plantuml](https://github.com/gmunguia/markdown-it-plantuml)** + katex 公式解析 [markdown-it-katex](https://github.com/waylonflinn/markdown-it-katex) + 元素属性书写 [markdown-it-attrs](https://github.com/arve0/markdown-it-attrs) + 表格解析增强,支持表格标题多行文本,列表等特性 [markdown-it-multimd-table](https://github.com/RedBug312/markdown-it-multimd-table) @@ -130,6 +131,7 @@ + [x] 状态栏 + [x] toc 生成 + [x] 内置终端 ++ [x] EChart 图表 + [ ] 代码块渲染增加行号 + [ ] 信息流,定时任务 + [ ] 标签支持 @@ -144,5 +146,4 @@ ![截图](./1.png) ![截图](./2.png) ![截图](./3.png) -![截图](./5.gif) -![截图](./6.png) +![截图](./4.gif) diff --git a/frontend/package.json b/frontend/package.json index 4c2484d3..00c56508 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -15,6 +15,7 @@ "dependencies": { "crypto-js": "^3.1.9-1", "dayjs": "^1.6.6", + "echarts": "^4.1.0", "github-markdown-css": "^2.10.0", "highlight.js": "^9.12.0", "lodash": "^4.17.10", diff --git a/frontend/src/components/EChartsPlugin.js b/frontend/src/components/EChartsPlugin.js new file mode 100644 index 00000000..159f071b --- /dev/null +++ b/frontend/src/components/EChartsPlugin.js @@ -0,0 +1,85 @@ +import echarts from 'echarts' +import CryptoJS from 'crypto-js' + +const renderHtml = code => { + const id = `echart-${CryptoJS.MD5(code).toString()}-${Math.random().toString(36).substr(2)}` + + return `
` +} + +const EChartsPlugin = md => { + const temp = md.renderer.rules.fence.bind(md.renderer.rules) + + md.renderer.rules.fence = (tokens, idx, options, env, slf) => { + const token = tokens[idx] + const code = token.content.trim() + if (token.info === 'js' && code.split(/\n/)[0].trim().includes('--echarts--')) { + return renderHtml(code) + } + + return temp(tokens, idx, options, env, slf) + } +} + +let charts = {} + +EChartsPlugin.update = (theme = 'dark', animation = undefined, renderImg = false) => { + Object.values(charts).forEach(x => x.chart.dispose()) + charts = {} + + for (let ele of document.getElementsByClassName('echarts')) { + try { + const id = ele.getAttribute('id') + const code = ele.dataset['code'] + + if (code) { + const chart = echarts.init(ele, theme) + // eslint-disable-next-line + eval(`(${decodeURIComponent(code)})(chart)`) + + if (animation !== undefined) { + chart.setOption({animation}) + } + + let img = null + + if (renderImg) { + img = new Image() + img.width = ele.clientWidth + img.height = ele.clientHeight + img.src = chart.getDataURL() + } + + charts[id] = { chart, img } + } + } catch (error) { + ele.innerText = error + } + } +} + +EChartsPlugin.preparePrint = () => { + EChartsPlugin.update('light', false, true) + + for (let ele of document.getElementsByClassName('echarts')) { + while (ele.firstChild) { + ele.firstChild.remove() + } + + const id = ele.getAttribute('id') + + if (charts[id] && charts[id].img) { + ele.appendChild(charts[id].img) + } + } +} + +window.addEventListener('resize', () => { + Object.values(charts).forEach(x => x.chart.resize()) +}) + +window.addEventListener('beforeprint', () => { + EChartsPlugin.update('light', false) +}) + +export default EChartsPlugin diff --git a/frontend/src/components/View.vue b/frontend/src/components/View.vue index fad3e9df..ded939b7 100644 --- a/frontend/src/components/View.vue +++ b/frontend/src/components/View.vue @@ -46,6 +46,7 @@ import MultimdTable from 'markdown-it-multimd-table' import Highlight from 'highlight.js' import MarkdownItToc from './TocPlugin' +import MarkdownItECharts from './EChartsPlugin' import RunPlugin from './RunPlugin' import SourceLinePlugin from './SourceLinePlugin' import LinkTargetPlugin from './LinkTargetPlugin' @@ -95,6 +96,7 @@ export default { .use(LinkTargetPlugin) .use(MultimdTable, {enableMultilineRows: true}) .use(MarkdownItToc) + .use(MarkdownItECharts) } }, mounted () { @@ -105,6 +107,7 @@ export default { this.render = _.debounce(() => { this.$refs.view.innerHTML = this.markdown.render(this.replaceRelativeLink(this.value)) MermaidPlugin.update() + MarkdownItECharts.update() this.updateOutline() this.updateTodoCount() this.updatePlantumlDebounce() @@ -239,6 +242,8 @@ export default { } }, convertFile (type) { + MarkdownItECharts.preparePrint() + const baseUrl = location.origin + location.pathname.substring(0, location.pathname.lastIndexOf('/')) + '/' this.convert = { @@ -246,6 +251,7 @@ export default { html: this.$refs.view.outerHTML.replace(/src="api/g, `src="${baseUrl}api`), type } + MarkdownItECharts.update() setTimeout(() => { this.$refs.convertForm.submit() }, 300) @@ -267,6 +273,13 @@ export default { } + +