index.html 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8"/>
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
  6. <title>思维导图</title>
  7. <style>
  8. * {
  9. margin: 0;
  10. padding: 0;
  11. box-sizing: border-box;
  12. }
  13. #markmap {
  14. display: flex;
  15. width: 100%;
  16. height: 100vh;
  17. }
  18. </style>
  19. <script src="./dsbridge.js"></script>
  20. <script src="./d3.js"></script>
  21. <script src="./markmap-lib.js"></script>
  22. <script src="./markmap-view.js"></script>
  23. </head>
  24. <body>
  25. <svg id="markmap"></svg>
  26. </body>
  27. <script>
  28. const { markmap } = window;
  29. const { Transformer, Markmap, loadCSS, loadJS } = window.markmap;
  30. const transformer = new Transformer([]);
  31. const { scripts, styles } = transformer.getAssets();
  32. loadCSS(styles);
  33. loadJS(scripts, { getMarkmap: () => markmap });
  34. let mm;
  35. let index = 0;
  36. let title = "思维导图";
  37. let description = "";
  38. let mindmapRoot = null;
  39. const branchColors = {};
  40. const colors = ["#F63F2F", "#F6A24B", "#F7D422", "#02BB7B", "#4869FF", "#7416E6"];
  41. const svgEl = document.querySelector("#markmap");
  42. mm = Markmap.create(svgEl, {
  43. color: (node) => {
  44. const { depth, path, id } = node.state;
  45. // 根节点
  46. if (depth === 1) {
  47. return colors[0];
  48. }
  49. // 二级节点
  50. if (depth === 2) {
  51. if (!branchColors[path]) {
  52. branchColors[path] = {
  53. color: colors[index % colors.length],
  54. index: index,
  55. };
  56. index++;
  57. }
  58. return branchColors[path].color;
  59. }
  60. // 二级以下节点
  61. const rootPath = path.split(".")[1];
  62. return branchColors["1." + rootPath].color;
  63. },
  64. //duration: 0, // 动画时长
  65. maxWidth: 400, // 节点最大宽度
  66. });
  67. function updateValue(value) {
  68. const { root } = transformer.transform(value);
  69. mindmapRoot = root;
  70. mm.setData(root);
  71. mm.fit();
  72. }
  73. function mindMapSaveAsHtmlCreateFile() {
  74. const root = JSON.stringify(mindmapRoot);
  75. let templateHtml = `<!DOCTYPE html><html><head><meta charset="UTF-8"/><meta name="viewport"content="width=device-width, initial-scale=1.0"/><meta http-equiv="X-UA-Compatible"content="ie=edge"/><title>${title}</title><style>*{margin:0;padding:0}#markmap{display:block;width:100vw;height:100vh}</style></head><body><svg id="markmap"><use xlink:href=""><title>${title}</title></use><desc>${description
  76. .replace(/&/g, "&amp;")
  77. .replace(/</g, "&lt;")
  78. .replace(
  79. />/g,
  80. "&lt;"
  81. )}</desc></svg><script src="https://cdn.jsdelivr.net/npm/d3"><\/script><script src="https://cdn.jsdelivr.net/npm/markmap-view"><\/script><script>const root=${root};const{Markmap,loadCSS,loadJS}=window.markmap;const maxWidth=400;const branchColors={};const colors=["#F63F2F","#F6A24B","#F7D422","#02BB7B","#4869FF","#7416E6"];const styles="div{padding-bottom:0.12em!important} a {text-decoration:none} foreignObject {overflow:visible} strong{color:#333; font-size:0.95em!important; font-weight:600!important;} .hide, .hide *{color:transparent!important} .hide {background-color:#FFFFEC} .hide img {opacity:0} img[alt=h-25]{height:25px} img[alt=h-50]{height:50px} img[alt=h-75]{height:75px} img[alt=h-100]{height:100px} img[alt=h-125]{height:125px} img[alt=h-150]{height:150px} img[alt=h-175]{height:175px} img[alt=h-200]{height:200px} blockquote {width:400px!important; white-space: normal; text-align:justify; font-size:0.8em; line-height:1em; border:1px solid #aaa; padding:10px; border-radius:4px;} aside{font-size: 0.8em; display: inline-block!important; font-weight:normal; vertical-align: top} cite {font-style:inherit; font-family:serif; font-size:0.97em};";const options={duration:0,style:(id)=>styles,maxWidth:maxWidth,spacingVertical:8,paddingX:15,autoFit:true,color:(node)=>{const{depth,path,id}=node.state;if(depth===1){return colors[0]}if(depth===2){if(!branchColors[path]){branchColors[path]={color:colors[index%colors.length],index:index,};index++}return branchColors[path].color}const rootPath=path.split(".")[1];return branchColors["1."+rootPath].color},};Markmap.create("#markmap",options,root);<\/script><\/body><\/html>`;
  82. const file = new File([templateHtml], `${title}.html`, {
  83. type: "text/plain;charset=utf-8",
  84. });
  85. return fileToBytes(file);
  86. }
  87. async function mindMapSaveAsSvgCreateFile() {
  88. const file = new File([createSVG(svgEl.innerHTML)], `${title}.svg`, {
  89. type: "text/plain;charset=utf-8",
  90. });
  91. return createSVG(svgEl.innerHTML);
  92. }
  93. function createSVG(html) {
  94. const boundingBox = getBBox(svgEl);
  95. html = html.replace(/<br>/g, "<br/>");
  96. html = html.replace(/\n/g, " ");
  97. html =
  98. '<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"><svg id="markmap" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="' +
  99. svgEl.className["baseVal"] +
  100. '" style="width:100%; height:100%;" viewBox="' +
  101. boundingBox.x +
  102. " " +
  103. (boundingBox.y - 5) +
  104. " " +
  105. boundingBox.w +
  106. " " +
  107. (boundingBox.h + 30) +
  108. '">' +
  109. '<use xlink:href=""><title>' +
  110. title +
  111. "</title></use>" +
  112. "<desc>" +
  113. description.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&lt;") +
  114. "</desc>" +
  115. html.replace(/<title>.*<\/title>/, "") +
  116. "</svg>";
  117. return html;
  118. }
  119. async function fileToBytes(file) {
  120. const response = new Response(file);
  121. const arrayBuffer = await response.arrayBuffer();
  122. return new Uint8Array(arrayBuffer);
  123. }
  124. // 注册更新数据的方法
  125. dsBridge.register("updateValue", function (value) {
  126. description = value;
  127. updateValue(value);
  128. });
  129. // 导出
  130. dsBridge.registerAsyn("export", async (value, responseCallback) => {
  131. if (value) {
  132. title = value;
  133. }
  134. const bytes = await mindMapSaveAsSvgCreateFile();
  135. responseCallback(bytes);
  136. });
  137. </script>
  138. </html>