文章目录

  • 一. 调研
  • 1.常见树状图 | 思维导图
  • 2.对比结果
  • 二. 文件目录
  • 1. public\jsmind.css
  • 2. public\jsmind.js
  • 3. public\mind.js
  • 4. src\components\minder\DataMind.vue
  • 5. src\components\minder\Minder.vue
  • 三. 功能点实现
  • 1.介绍
  • 2.在 index.html 中引入 jsmind
  • 3.页面中引入 Minder 组件
  • 四、源码
  • 1. Minder.vue
  • 2. DataMinder.vue
  • 3. jsmind.css
  • 4. jsmind.js
  • 5.mind.js
  • 6. test.vue
  • 7. 运行效果

一. 调研

1.常见树状图 | 思维导图

  1. https://juejin.cn/post/6844904103298990093

  2. echarts
    https://echarts.apache.org/examples/zh/editor.html?c=tree-polyline

  3. https://juejin.cn/post/6844903615425937416

  4. https://bl.ocks.org/mbostock/4339083

  5. https://fperucic.github.io/treant-js/

  6. gojs
    https://gojs.net/latest/samples/decisionTree.html
    https://balkan.app/OrgChartJS/Demos/RoyalFamilyTree
    https://codepen.io/tutsplus/pen/MWedpoj

  7. 有复选框的treeNode
    https://devexpress.github.io/dotnet-eud/interface-elements-for-web/articles/tree-view/tree-view-nodes-checking.html


2.对比结果

拟采用的方法:

改造 jsmind 实现自定义的思维导图

Jsmind 的功能及使用见官方文档:

https://github.com/hizzgdev/jsmind/blob/master/docs/zh/index.md


二. 文件目录

1. public\jsmind.css

jsmind 插件自带的 css 文件,思维导图的样式文件。

2. public\jsmind.js

jsmind 插件自带的 js 文件,思维导图的逻辑实现。

3. public\mind.js

思维导图的数据和触发方法,数据挂载在 window 对象下,用于和 vue 框架中的内容交互。

4. src\components\minder\DataMind.vue

思维导图的业务调用组件,包括思维导图、标题栏和左上 tip 文字内容。

5. src\components\minder\Minder.vue

思维导图的核心组件,分为 5 种类型:defalut,check,label,label2,input,通过 type 传值配置对应样式。
!!!当然这只是我根据项目需求改造的几种样式,大家也可以自行阅读下面minder.vuejsmind.css以及jsmind.js进行个性化改造。


三. 功能点实现

1.介绍

Jsmind的功能及使用见官方文档:

https://github.com/hizzgdev/jsmind/blob/master/docs/zh/index.md
本demo采用 vue3+typescript+vite 实现,核心功能在 src\components\minder\Minder.vue 文件中实现。

2.在 index.html 中引入 jsmind

如下图所示:

<link rel="stylesheet" href="/jsmind.css" />
<script type="text/javascript" src="/jsmind.js"></script>

3.页面中引入 Minder 组件

如下所示:

4.传入的数据结构,如下所示:

   (window as any).mindData = {id: "root",topic: "根节点名字",number: [88],children: [{id: "easy",topic: "规章制度",children: [{ id: "easy1", topic: "请休假制度" },{ id: "easy2", topic: "考勤制度" },],},{id: "open",topic: "岗位职责",children: [{id: "open1",topic: "人事部职责",children: [{ id: "open1-1", topic: "行政管理" },{ id: "open1-2", topic: "人事管理" },],},{id: "open2",topic: "信息部职责",children: [{ id: "open2-1", topic: "信息安全" },{ id: "open2-2", topic: "信息排查" },{ id: "open2-3", topic: "信息汇总" },{ id: "open2-4", topic: "ERP" },],},{id: "open3",topic: "生产车间",children: [{ id: "open3-1", topic: "安全制度" },{ id: "open3-2", topic: "车间操作手册" },],},],},{id: "powerful",topic: "员工福利",number,children: [{ id: "powerful1", topic: "雪天", tip: "3366" },{ id: "powerful2", topic: "年假", tip: "98999" },{id: "powerful3",topic: "法定节假日",number,},{ id: "powerful4", topic: "生日祝福" },{id: "powerful5",topic: "成长与进步",children: [{ id: "powerful5-1", topic: "员工培训" }],},],},],};

其中,id,topic,children 的用法见官方文档,number 为定制化展示的数据部分,如下图所示:

当 type 为 label2 时,number 为数组,对应关系如下图所示:

  1. type 分为 5 种类型:default,check,label,label2,input,当 type 为 default 类型时,传值 type=“”即可,页面效果如下:

当 type 为 check 类型时,页面效果如下:

当 type 为 label 类型时,页面效果如下:

当 type 为 label2 类型时,页面效果如下:

当 type 为 input 类型时,页面效果如下:

  1. 参数配置见下图,可根据实际需求进行调整:

四、源码

1. Minder.vue

<template><div class="minder" :id="jsmind_container_id"></div>
</template><script lang="ts">
import {defineComponent,reactive,toRefs,onMounted,computed,watch,
} from "vue";
declare global {interface Window {metaData: any;uncheckedData: any;}
}export default defineComponent({name: "minder",props: {data: {type: Object,default: {},},type: {//type:defalut,check,label,label2,inputtype: String,default: "",},jsmind_container_id: {type: String,default: "jsmind_container",},rootValue: {type: Number,default: 0,},jsmindType: {type: Number,default: 0,},},setup(props) {console.log("data,type,id", props);const state = reactive({name: "",});let jm: any;const jwidth = {"": 140,check: 140,label: 158,label2: 216,input: 178,};const mind = computed(() => ({meta: {name: "jsMind",author: "",version: "0.2",},format: "node_tree",data: props.data,}));const handleMind = (data: any) => {console.log("props", props);const { id, topic, children, number = [50], topic_en, tip } = data;console.log("data", data);//如果是div,不是字符串,不予处理if (topic.includes("<div")) return;const isParent: boolean = children && children.length > 0;const isRoot: boolean = id === "root";const jdom = getDomByType(props.type,topic,isParent,id,topic_en,number);const jtip = getTipByType(props.type, tip, isParent, number);if (isRoot) {//根节点单独处理data.topic = getRootByType(props.type, topic, props.rootValue);}// else if (props.type === "label2" && isParent) {//   //label2类型父节点底部有文字//   data.topic = `//   <div class="jmnnode-base">//     ${jdom}//     ${jtip}//   </div>`;// }else if (props.type != "label2" && !isParent) {//其他类型叶子节点底部有文字data.topic = `<div class="jmnnode-base">${jdom}${jtip}</div>`;}//20211225---label2只有叶子结点显示均值方差else if (props.type == "label2" && !isParent) {//其他类型叶子节点底部有文字data.topic = `<div class="jmnnode-base">${jdom}${jtip}</div>`;} else {data.topic = jdom;}if (isParent) {for (let child of children) {handleMind(child);}}};const getDomByType = (type: string,topic: string,isParent: boolean,id: string,topic_en: string,number?: number | number[]) => {// console.log("type##########", type);let resDom = "";let jclass = isParent? `class="jmnnode-dom jmnnode-dom-blue"`: `class="jmnnode-dom"`;switch (type) {case "check":if (isParent) {resDom = `<svg-icon icon-class="icon_unbiased"></svg-icon>  <div ${jclass} style="width:${jwidth[type]}px">${topic}</div>`;} else {resDom = `<div ${jclass} style="width:${jwidth[type]}px"><span>${topic}</span></div> <input type="checkbox" οnclick="handleClick(this.checked,'${topic}','${id}','${topic_en}')"/>`;}break;case "label":jclass = isParent? `class="jmnnode-dom jmnnode-dom-blue jmnnode-dom-label"`: `class="jmnnode-dom jmnnode-dom-label"`;resDom = `<div ${jclass} style="width:${jwidth[type]}px"><span>${topic}</span><div class="jmnnode-dom-number">${number || 0}</div></div>`;break;case "label2":jclass = isParent? `class="jmnnode-dom jmnnode-dom-blue jmnnode-dom-label"`: `class="jmnnode-dom jmnnode-dom-label"`;const [num1, num2, num3, num4] = (number as number[]) || [0, 0, 0, 0];//20211226---修改只有叶子结点显示权重方差if (isParent) {resDom = `<div ${jclass} style="width:${jwidth[type] - 30}px"><span>${topic}</span><div class="jmnnode-dom-avg"><div class="jmnnode-dom-number">${num1?.toFixed(2)}</div></div></div>`;} else {resDom = `<div ${jclass} style="width:${jwidth[type] - 30}px"><span>${topic}</span><div class="jmnnode-dom-avg"><div class="jmnnode-dom-number">${num1?.toFixed(2)}</div><div class="jmnnode-dom-number jmnnode-dom-green">${num2?.toFixed(2)}</div></div></div>`;}break;case "input":jclass = isParent? `class="jmnnode-dom jmnnode-dom-blue jmnnode-dom-input"`: `class="jmnnode-dom jmnnode-dom-input"`;resDom = `<div ${jclass} style="width:${jwidth[type]}px"><span>${topic}</span><input class="jmnnode-dom-input-right" value='${number}' οnchange="handleInput(this.value,'${topic}','${id}')"/></div>`;break;default:if (topic == "完整性") {resDom = `  <div ${jclass} style="width:${jwidth["check"]}px"><img src="/src/assets/img/icon_whole.png" width="22" height="22" style=" position: absolute;left: 12px;top: 16px;" />${topic}</div>`;} else if (topic == "现实性") {resDom = `  <div ${jclass} style="width:${jwidth["check"]}px"><img src="/src/assets/img/icon_clock.png" width="22" height="22" style=" position: absolute;left: 12px;top: 16px;" />${topic}</div>`;} else if (topic == "准确性") {resDom = `  <div ${jclass} style="width:${jwidth["check"]}px"><img src="/src/assets/img/icon_right.png" width="22" height="22" style=" position: absolute;left: 12px;top: 16px;" />${topic}</div>`;} else if (topic == "无偏性") {resDom = `  <div ${jclass} style="width:${jwidth["check"]}px"><img src="/src/assets/img/icon_unbiased.png" width="22" height="22" style=" position: absolute;left: 12px;top: 16px;" />${topic}</div>`;} else if (topic == "规范性") {resDom = `  <div ${jclass} style="width:${jwidth["check"]}px"><img src="/src/assets/img/icon_standard.png" width="22" height="22" style=" position: absolute;left: 12px;top: 16px;" />${topic}</div>`;} else {resDom = `  <div ${jclass} style="width:${jwidth["check"]}px">${topic}</div>`;}}return resDom;};const getTipByType = (type: string,tip: string = "0",isParent: boolean,number: number[] = [0, 0, 0, 0]) => {let resDom = "";switch (type) {case "label2":const [, , num3, num4] = (number as number[]) || [0, 0, 0, 0];resDom = `<div class="jmnnode-tip jmnnode-tip-avg" style="width:${jwidth[type]}px">方差:<div class="jmnnode-tip-blue" style="margin-right:32px">${num3?.toFixed(2)}</div>均值:<div class="jmnnode-tip-yellow">${num4?.toFixed(2)}</div></div>`;break;default:resDom = `<div class="jmnnode-tip" style="width:${jwidth["check"]}px">(${tip})</div>`;}return resDom;};const getRootByType = (type: string, topic: string, rootValue: number) => {let resDom = "";switch (type) {case "label2":resDom = `<div class="jmnnode-base"><div class="jmnnode-dom">${topic}</div><div class="jmnnode-root-line"></div><div class="jmnnode-root-tip"><div class="jmnnode-root-tip-title">综合评估:</div><div class="jmnnode-root-tip-blue">${rootValue || 0}</div></div></div>`;break;default:resDom = `<div class="jmnnode-base"><div class="jmnnode-dom" style="display:block" > <img src="/src/assets/img/pic_demo.png" width="33" height="33" />${topic}</div><div class="jmnnode-root-line"></div></div>`;}return resDom;};const options = {container: props.jsmind_container_id as String, //容器的IDeditable: false, // 是否启用编辑theme: "primary", //主题mode: "side", // 显示模式========full - 子节点动态分布在根节点两侧 [默认值] side - 子节点只分布在根节点右侧layout: {hspace: 50, // 节点之间的水平间距vspace: 40, // 节点之间的垂直间距pspace: 13, // 节点与连接线之间的水平间距(用于容纳节点收缩/展开控制器)},//options的属性//container : '',         // [必选] 容器的ID// editable : false,       // 是否启用编辑// theme : null,           // 主题// mode :'full',           // 显示模式========full - 子节点动态分布在根节点两侧 [默认值] side - 子节点只分布在根节点右侧// support_html : true,    // 是否支持节点里的HTML元素view: {hmargin: 0, // 思维导图距容器外框的最小水平距离vmargin: 100, // 思维导图距容器外框的最小垂直距离line_width: 1, // 思维导图线条的粗细line_color: "#C6C6C9", // 思维导图线条的颜色},// layout:{//     hspace:30,          // 节点之间的水平间距//     vspace:20,          // 节点之间的垂直间距//     pspace:13           // 节点与连接线之间的水平间距(用于容纳节点收缩/展开控制器)// },};if (props.jsmindType == 1) {options.layout = {hspace: 180, // 节点之间的水平间距vspace: 40, // 节点之间的垂直间距pspace: 13, // 节点与连接线之间的水平间距(用于容纳节点收缩/展开控制器)};}//handleMind(mind.value.data);const showMinder = () => {console.log(props);console.log("handleMind", JSON.parse(JSON.stringify(mind.value.data)));window.metaData = JSON.parse(JSON.stringify(mind.value.data));window.uncheckedData = JSON.parse(JSON.stringify(mind.value.data));handleMind(mind.value.data);// console.log("handleMind2", mind.value.data);jm.show(mind.value);//jm.disable_edit();//禁止编制jm.expand_all(); //展开全部节点// jm.add_node(parent_node, nodeid, topic, data);//添加节点// setHeight();};// const setHeight = () => {//   setTimeout(() => {//     const dom = document.querySelector("jmnodes") as HTMLDivElement;//     // const btn_dom = document.querySelector(//     //   ".next-step-btn"//     // ) as HTMLDivElement;//     (//       document.querySelector(//         `#${props.jsmind_container_id}`//       ) as HTMLDivElement//     ).style.height = `${dom.clientHeight}px`;//   }, 0);// };watch(() => props.data,(newVal, oldVal) => {if (newVal.id) showMinder();});onMounted(() => {// @ts-ignore// if (jsmindType == 1) {jm = new jsMind(options);// } else {//   jm = new jsMind(options);// }jm.add_event_listener(function (type, data) {console.log("this", jm.view.size.h);const dom = document.querySelector("jmnodes") as HTMLDivElement;console.log("dom.clientHeight", dom.clientHeight);(document.querySelector(`#${props.jsmind_container_id}`) as HTMLDivElement).style.minHeight = `${dom.clientHeight}px`;});if (props.data.id) showMinder();});return {...toRefs(state),};},
});
</script>
<style lang="scss" scoped>
.minder {width: 100%;height: 100%;.jmnode-icon {position: absolute;left: 12px;top: 16px;}
}
</style>

2. DataMinder.vue

<template><div class="data-mind"><!-- <div class="data-mind-title" v-if="type != 'label2'">指标和参数配置</div> --><div class="data-mind-header"><div class="data-mind-tip"><div class="data-mind-tip__label"></div><div class="data-mind-tip__name">质量特性</div></div><div class="data-mind-tip"><div class="data-mind-tip__label2"></div><div class="data-mind-tip__name">度量指标</div></div></div><minder:data="data":type="type":jsmind_container_id="jsmind_container_id":rootValue="rootValue":jsmindType="jsmindType"></minder></div>
</template><script lang="ts">
import { defineComponent, reactive, toRefs, computed } from "vue";
import Minder from "@/components/minder/Minder.vue";export default defineComponent({name: "DataMind",components: { Minder },props: {data: {type: Object,default: {},},type: {//type:defalut,check,label,label2,inputtype: String,default: "",},jsmind_container_id: {type: String,default: "jsmind_container",},rootValue: {type: Number,default: 0,},jsmindType: {type: Number,default: 0,},},setup() {const state = reactive({name: "", //type:defalut,check,label,label2,input});return {...toRefs(state),};},
});
</script>
<style lang="scss" scoped>
$height: 48px;.data-mind {width: 100%;height: 100%;position: relative;&-title {width: 100%;height: $height;background: rgba(84, 115, 231, 0.09);display: flex;align-items: center;padding: 0 20px;font-size: 16px;font-weight: 600;color: #3b3b5b;}&-header {position: absolute;padding: 27px 38px;}&-tip {// position: absolute;// left: 16px;// top: $height + 20;font-size: 14px;color: #9b9ba5;font-weight: 400;display: flex;align-items: center;&__label {width: 28px;height: 12px;background: #f4f7ff;border: 1px solid rgba(223, 223, 223, 1);border-radius: 2px;margin-right: 10px;}&__label2 {width: 28px;height: 12px;background: #ffffff;border: 1px solid rgba(223, 223, 223, 1);border-radius: 2px;margin-right: 10px;}}.circle-leaf {border-radius: 50%;width: 9px;height: 9px;background: rgba(84, 115, 231, 0.7);margin: 0 40px 0 4px;}&-line {line-height: 22px;}.circle-label {background: rgba(84, 115, 231, 0.2);border: 1px solid #5473e7;border-radius: 50%;width: 9px;height: 9px;margin: 0 0 0 8px;}
}
.square-blue {width: 9px;height: 9px;background: #5473e7;border-radius: 1px;margin-right: 32px;margin-left: 8px;
}
.square-green {width: 9px;height: 9px;background: #44d7b6;border-radius: 1px;margin-right: 32px;margin-left: 8px;
}
.square-purple {width: 12px;height: 4px;background: #6236ff;margin-right: 32px;margin-left: 8px;
}
.square-orange {width: 12px;height: 4px;background: #f7b500;margin-left: 8px;
}
.square-white {width: 9px;height: 9px;background: #ffffff;border-radius: 1px;border: 1px solid #dfdfdf;
}
.weight-block {line-height: 22px;display: flex;align-items: center;margin-left: 32px;
}
.label2-block {line-height: 22px;display: flex;align-items: center;
}
</style>

3. jsmind.css

/** Released under BSD License* Copyright (c) 2014-2015 hizzgdev@163.com* * Project Home:*   https://github.com/hizzgdev/jsmind/*//* important section */
.jsmind-inner {position: relative;overflow: auto;width: 100%;height: 100%;
}/*box-shadow:0 0 2px #000;*/
.jsmind-inner {moz-user-select: -moz-none;-moz-user-select: none;-o-user-select: none;-khtml-user-select: none;-webkit-user-select: none;-ms-user-select: none;user-select: none;
}/* z-index:1 */
canvas {position: absolute;z-index: 1;
}/* z-index:2 */
jmnodes {position: absolute;z-index: 2;background-color: rgba(0, 0, 0, 0);
}/*background color is necessary*/
jmnode {position: absolute;cursor: default;max-width: 400px;white-space: nowrap;/* overflow: hidden; */text-overflow: ellipsis;
}jmexpander {position: absolute;width: 14px;height: 2px;margin-top: 6px;color: #b9b9bd;background: #c6c6c9;font-size: 12px;text-align: center;cursor: pointer;
}/* default theme */
jmnode {/* padding: 10px 20px; */background-color: #fff;color: #333;/* border-radius: 20px; *//* box-shadow: 1px 1px 1px #666; */font: 16px/1.125 Verdana, Arial, Helvetica, sans-serif;
}jmnode:hover {box-shadow: 2px 2px 8px #000;background-color: #ebebeb;color: #333;
}jmnode.selected {background-color: #11f;color: #fff;box-shadow: 2px 2px 8px #000;
}jmnode.root {font-size: 24px;
}jmexpander:hover {border-color: #000;
}@media screen and (max-device-width: 1024px) {jmnode {padding: 5px;border-radius: 3px;font-size: 14px;}jmnode.root {font-size: 21px;}
}/* primary theme */
jmnodes.theme-primary jmnode {/* background-color: #428bca; */color: #fff;/* border-color: #357ebd; */
}jmnodes.theme-primary jmnode:hover {background-color: #3276b1;border-color: #285e8e;
}jmnodes.theme-primary jmnode.selected {background-color: #f1c40f;color: #fff;
}jmnodes.theme-primary jmnode.root {}jmnodes.theme-primary jmexpander {}jmnodes.theme-primary jmexpander:hover {}/* warning theme */
jmnodes.theme-warning jmnode {background-color: #f0ad4e;border-color: #eea236;color: #fff;
}jmnodes.theme-warning jmnode:hover {background-color: #ed9c28;border-color: #d58512;
}jmnodes.theme-warning jmnode.selected {background-color: #11f;color: #fff;
}jmnodes.theme-warning jmnode.root {}jmnodes.theme-warning jmexpander {}jmnodes.theme-warning jmexpander:hover {}/* danger theme */
jmnodes.theme-danger jmnode {background-color: #d9534f;border-color: #d43f3a;color: #fff;
}jmnodes.theme-danger jmnode:hover {background-color: #d2322d;border-color: #ac2925;
}jmnodes.theme-danger jmnode.selected {background-color: #11f;color: #fff;
}jmnodes.theme-danger jmnode.root {}jmnodes.theme-danger jmexpander {}jmnodes.theme-danger jmexpander:hover {}/* success theme */
jmnodes.theme-success jmnode {background-color: #5cb85c;border-color: #4cae4c;color: #fff;
}jmnodes.theme-success jmnode:hover {background-color: #47a447;border-color: #398439;
}jmnodes.theme-success jmnode.selected {background-color: #11f;color: #fff;
}jmnodes.theme-success jmnode.root {}jmnodes.theme-success jmexpander {}jmnodes.theme-success jmexpander:hover {}/* info theme */
jmnodes.theme-info jmnode {background-color: #5dc0de;border-color: #46b8da;color: #fff;
}jmnodes.theme-info jmnode:hover {background-color: #39b3d7;border-color: #269abc;
}jmnodes.theme-info jmnode.selected {background-color: #11f;color: #fff;
}jmnodes.theme-info jmnode.root {}jmnodes.theme-info jmexpander {}jmnodes.theme-info jmexpander:hover {}/* greensea theme */
jmnodes.theme-greensea jmnode {background-color: #1abc9c;color: #fff;
}jmnodes.theme-greensea jmnode:hover {background-color: #16a085;
}jmnodes.theme-greensea jmnode.selected {background-color: #11f;color: #fff;
}jmnodes.theme-greensea jmnode.root {}jmnodes.theme-greensea jmexpander {}jmnodes.theme-greensea jmexpander:hover {}/* nephrite theme */
jmnodes.theme-nephrite jmnode {background-color: #2ecc71;color: #fff;
}jmnodes.theme-nephrite jmnode:hover {background-color: #27ae60;
}jmnodes.theme-nephrite jmnode.selected {background-color: #11f;color: #fff;
}jmnodes.theme-nephrite jmnode.root {}jmnodes.theme-nephrite jmexpander {}jmnodes.theme-nephrite jmexpander:hover {}/* belizehole theme */
jmnodes.theme-belizehole jmnode {background-color: #3498db;color: #fff;
}jmnodes.theme-belizehole jmnode:hover {background-color: #2980b9;
}jmnodes.theme-belizehole jmnode.selected {background-color: #11f;color: #fff;
}jmnodes.theme-belizehole jmnode.root {}jmnodes.theme-belizehole jmexpander {}jmnodes.theme-belizehole jmexpander:hover {}/* wisteria theme */
jmnodes.theme-wisteria jmnode {background-color: #9b59b6;color: #fff;
}jmnodes.theme-wisteria jmnode:hover {background-color: #8e44ad;
}jmnodes.theme-wisteria jmnode.selected {background-color: #11f;color: #fff;
}jmnodes.theme-wisteria jmnode.root {}jmnodes.theme-wisteria jmexpander {}jmnodes.theme-wisteria jmexpander:hover {}/* asphalt theme */
jmnodes.theme-asphalt jmnode {background-color: #34495e;color: #fff;
}jmnodes.theme-asphalt jmnode:hover {background-color: #2c3e50;
}jmnodes.theme-asphalt jmnode.selected {background-color: #11f;color: #fff;
}jmnodes.theme-asphalt jmnode.root {}jmnodes.theme-asphalt jmexpander {}jmnodes.theme-asphalt jmexpander:hover {}/* orange theme */
jmnodes.theme-orange jmnode {background-color: #f1c40f;color: #fff;
}jmnodes.theme-orange jmnode:hover {background-color: #f39c12;
}jmnodes.theme-orange jmnode.selected {background-color: #11f;color: #fff;
}jmnodes.theme-orange jmnode.root {}jmnodes.theme-orange jmexpander {}jmnodes.theme-orange jmexpander:hover {}/* pumpkin theme */
jmnodes.theme-pumpkin jmnode {background-color: #e67e22;color: #fff;
}jmnodes.theme-pumpkin jmnode:hover {background-color: #d35400;
}jmnodes.theme-pumpkin jmnode.selected {background-color: #11f;color: #fff;
}jmnodes.theme-pumpkin jmnode.root {}jmnodes.theme-pumpkin jmexpander {}jmnodes.theme-pumpkin jmexpander:hover {}/* pomegranate theme */
jmnodes.theme-pomegranate jmnode {background-color: #e74c3c;color: #fff;
}jmnodes.theme-pomegranate jmnode:hover {background-color: #c0392b;
}jmnodes.theme-pomegranate jmnode.selected {background-color: #11f;color: #fff;
}jmnodes.theme-pomegranate jmnode.root {}jmnodes.theme-pomegranate jmexpander {}jmnodes.theme-pomegranate jmexpander:hover {}/* clouds theme */
jmnodes.theme-clouds jmnode {background-color: #ecf0f1;color: #333;
}jmnodes.theme-clouds jmnode:hover {background-color: #bdc3c7;
}jmnodes.theme-clouds jmnode.selected {background-color: #11f;color: #fff;
}jmnodes.theme-clouds jmnode.root {}jmnodes.theme-clouds jmexpander {}jmnodes.theme-clouds jmexpander:hover {}/* asbestos theme */
jmnodes.theme-asbestos jmnode {background-color: #95a5a6;color: #fff;
}jmnodes.theme-asbestos jmnode:hover {background-color: #7f8c8d;
}jmnodes.theme-asbestos jmnode.selected {background-color: #11f;color: #fff;
}jmnodes.theme-asbestos jmnode.root {}jmnodes.theme-asbestos jmexpander {}jmnodes.theme-asbestos jmexpander:hover {}

4. jsmind.js


/** Released under BSD License* Copyright (c) 2014-2016 hizzgdev@163.com** Project Home:*   https://github.com/hizzgdev/jsmind/*/;(function ($w) {'use strict';// set 'jsMind' as the library name.// __name__ should be a const value, Never try to change it easily.var __name__ = 'jsMind';// library versionvar __version__ = '0.4.6';// authorvar __author__ = 'hizzgdev@163.com';// an noop function definevar _noop = function () {};var logger = (typeof console === 'undefined') ? {log: _noop, debug: _noop, error: _noop, warn: _noop, info: _noop} : console;// check global variablesif (typeof module === 'undefined' || !module.exports) {if (typeof $w[__name__] != 'undefined') {logger.log(__name__ + ' has been already exist.');return;}}// shortcut of methods in domvar $d = $w.document;var $g = function (id) {return $d.getElementById(id);};var $c = function (tag) {return $d.createElement(tag);};var $t = function (n, t) {if (n.hasChildNodes()) {n.firstChild.nodeValue = t;} else {n.appendChild($d.createTextNode(t));}};var $h = function (n, t) {if (t instanceof HTMLElement) {n.innerHTML = '';n.appendChild(t)} else {n.innerHTML = t;}};// detect isElementvar $i = function (el) {return !!el && (typeof el === 'object') && (el.nodeType === 1) && (typeof el.style === 'object') && (typeof el.ownerDocument === 'object');};if (typeof String.prototype.startsWith != 'function') {String.prototype.startsWith = function (p) {return this.slice(0, p.length) === p;};}var DEFAULT_OPTIONS = {container: '',   // id of the containereditable: false, // you can change it in your optionstheme: null,mode: 'full',     // full or sidesupport_html: true,view: {hmargin: 100,vmargin: 50,line_width: 2,line_color: '#555'},layout: {hspace: 30,vspace: 20,pspace: 13},default_event_handle: {enable_mousedown_handle: true,enable_click_handle: true,enable_dblclick_handle: true},shortcut: {enable: true,handles: {},mapping: {addchild: 45, // Insertaddbrother: 13, // Entereditnode: 113,// F2delnode: 46, // Deletetoggle: 32, // Spaceleft: 37, // Leftup: 38, // Upright: 39, // Rightdown: 40, // Down}},};// core objectvar jm = function (options) {jm.current = this;this.version = __version__;var opts = {};jm.util.json.merge(opts, DEFAULT_OPTIONS);jm.util.json.merge(opts, options);if (!opts.container) {logger.error('the options.container should not be null or empty.');return;}this.options = opts;this.inited = false;this.mind = null;this.event_handles = [];this.init();};// ============= static object =============================================jm.direction = {left: -1, center: 0, right: 1};jm.event_type = {show: 1, resize: 2, edit: 3, select: 4};jm.node = function (sId, iIndex, sTopic, oData, bIsRoot, oParent, eDirection, bExpanded) {if (!sId) {logger.error('invalid nodeid');return;}if (typeof iIndex != 'number') {logger.error('invalid node index');return;}if (typeof bExpanded === 'undefined') {bExpanded = true;}this.id = sId;this.index = iIndex;this.topic = sTopic;this.data = oData || {};this.isroot = bIsRoot;this.parent = oParent;this.direction = eDirection;this.expanded = !!bExpanded;this.children = [];this._data = {};};jm.node.compare = function (node1, node2) {// '-1' is alwary the lastvar r = 0;var i1 = node1.index;var i2 = node2.index;if (i1 >= 0 && i2 >= 0) {r = i1 - i2;} else if (i1 == -1 && i2 == -1) {r = 0;} else if (i1 == -1) {r = 1;} else if (i2 == -1) {r = -1;} else {r = 0;}//logger.debug(i1+' <> '+i2+'  =  '+r);return r;};jm.node.inherited = function (pnode, node) {if (!!pnode && !!node) {if (pnode.id === node.id) {return true;}if (pnode.isroot) {return true;}var pid = pnode.id;var p = node;while (!p.isroot) {p = p.parent;if (p.id === pid) {return true;}}}return false;};jm.node.prototype = {get_location: function () {var vd = this._data.view;console.log('vd',vd);return {x: vd.abs_x,y: vd.abs_y};},get_size: function () {var vd = this._data.view;return {w: vd.width,h: vd.height}}};jm.mind = function () {this.name = null;this.author = null;this.version = null;this.root = null;this.selected = null;this.nodes = {};};jm.mind.prototype = {get_node: function (nodeid) {if (nodeid in this.nodes) {return this.nodes[nodeid];} else {logger.warn('the node[id=' + nodeid + '] can not be found');return null;}},set_root: function (nodeid, topic, data) {if (this.root == null) {this.root = new jm.node(nodeid, 0, topic, data, true);this._put_node(this.root);} else {logger.error('root node is already exist');}},add_node: function (parent_node, nodeid, topic, data, idx, direction, expanded) {if (!jm.util.is_node(parent_node)) {var the_parent_node = this.get_node(parent_node);if (!the_parent_node) {logger.error('the parent_node[id=' + parent_node + '] can not be found.');return null;} else {return this.add_node(the_parent_node, nodeid, topic, data, idx, direction, expanded);}}var nodeindex = idx || -1;var node = null;if (parent_node.isroot) {var d = jm.direction.right;if (isNaN(direction)) {var children = parent_node.children;var children_len = children.length;var r = 0;for (var i = 0; i < children_len; i++) {if (children[i].direction === jm.direction.left) {r--;} else {r++;}}d = (children_len > 1 && r > 0) ? jm.direction.left : jm.direction.right} else {d = (direction != jm.direction.left) ? jm.direction.right : jm.direction.left;}node = new jm.node(nodeid, nodeindex, topic, data, false, parent_node, d, expanded);} else {node = new jm.node(nodeid, nodeindex, topic, data, false, parent_node, parent_node.direction, expanded);}if (this._put_node(node)) {parent_node.children.push(node);this._reindex(parent_node);} else {logger.error('fail, the nodeid \'' + node.id + '\' has been already exist.');node = null;}return node;},insert_node_before: function (node_before, nodeid, topic, data) {if (!jm.util.is_node(node_before)) {var the_node_before = this.get_node(node_before);if (!the_node_before) {logger.error('the node_before[id=' + node_before + '] can not be found.');return null;} else {return this.insert_node_before(the_node_before, nodeid, topic, data);}}var node_index = node_before.index - 0.5;return this.add_node(node_before.parent, nodeid, topic, data, node_index);},get_node_before: function (node) {if (!jm.util.is_node(node)) {var the_node = this.get_node(node);if (!the_node) {logger.error('the node[id=' + node + '] can not be found.');return null;} else {return this.get_node_before(the_node);}}if (node.isroot) {return null;}var idx = node.index - 2;if (idx >= 0) {return node.parent.children[idx];} else {return null;}},insert_node_after: function (node_after, nodeid, topic, data) {if (!jm.util.is_node(node_after)) {var the_node_after = this.get_node(node_before);if (!the_node_after) {logger.error('the node_after[id=' + node_after + '] can not be found.');return null;} else {return this.insert_node_after(the_node_after, nodeid, topic, data);}}var node_index = node_after.index + 0.5;return this.add_node(node_after.parent, nodeid, topic, data, node_index);},get_node_after: function (node) {if (!jm.util.is_node(node)) {var the_node = this.get_node(node);if (!the_node) {logger.error('the node[id=' + node + '] can not be found.');return null;} else {return this.get_node_after(the_node);}}if (node.isroot) {return null;}var idx = node.index;var brothers = node.parent.children;if (brothers.length >= idx) {return node.parent.children[idx];} else {return null;}},move_node: function (node, beforeid, parentid, direction) {if (!jm.util.is_node(node)) {var the_node = this.get_node(node);if (!the_node) {logger.error('the node[id=' + node + '] can not be found.');return null;} else {return this.move_node(the_node, beforeid, parentid, direction);}}if (!parentid) {parentid = node.parent.id;}return this._move_node(node, beforeid, parentid, direction);},_flow_node_direction: function (node, direction) {if (typeof direction === 'undefined') {direction = node.direction;} else {node.direction = direction;}var len = node.children.length;while (len--) {this._flow_node_direction(node.children[len], direction);}},_move_node_internal: function (node, beforeid) {if (!!node && !!beforeid) {if (beforeid == '_last_') {node.index = -1;this._reindex(node.parent);} else if (beforeid == '_first_') {node.index = 0;this._reindex(node.parent);} else {var node_before = (!!beforeid) ? this.get_node(beforeid) : null;if (node_before != null && node_before.parent != null && node_before.parent.id == node.parent.id) {node.index = node_before.index - 0.5;this._reindex(node.parent);}}}return node;},_move_node: function (node, beforeid, parentid, direction) {if (!!node && !!parentid) {if (node.parent.id != parentid) {// remove from parent's childrenvar sibling = node.parent.children;var si = sibling.length;while (si--) {if (sibling[si].id == node.id) {sibling.splice(si, 1);break;}}node.parent = this.get_node(parentid);node.parent.children.push(node);}if (node.parent.isroot) {if (direction == jsMind.direction.left) {node.direction = direction;} else {node.direction = jm.direction.right;}} else {node.direction = node.parent.direction;}this._move_node_internal(node, beforeid);this._flow_node_direction(node);}return node;},remove_node: function (node) {if (!jm.util.is_node(node)) {var the_node = this.get_node(node);if (!the_node) {logger.error('the node[id=' + node + '] can not be found.');return false;} else {return this.remove_node(the_node);}}if (!node) {logger.error('fail, the node can not be found');return false;}if (node.isroot) {logger.error('fail, can not remove root node');return false;}if (this.selected != null && this.selected.id == node.id) {this.selected = null;}// clean all subordinate nodesvar children = node.children;var ci = children.length;while (ci--) {this.remove_node(children[ci]);}// clean all childrenchildren.length = 0;// remove from parent's childrenvar sibling = node.parent.children;var si = sibling.length;while (si--) {if (sibling[si].id == node.id) {sibling.splice(si, 1);break;}}// remove from global nodesdelete this.nodes[node.id];// clean all propertiesfor (var k in node) {delete node[k];}// remove it's selfnode = null;//delete node;return true;},_put_node: function (node) {if (node.id in this.nodes) {logger.warn('the nodeid \'' + node.id + '\' has been already exist.');return false;} else {this.nodes[node.id] = node;return true;}},_reindex: function (node) {if (node instanceof jm.node) {node.children.sort(jm.node.compare);for (var i = 0; i < node.children.length; i++) {node.children[i].index = i + 1;}}},};jm.format = {node_tree: {example: {"meta": {"name": __name__,"author": __author__,"version": __version__},"format": "node_tree","data": {"id": "root", "topic": "jsMind Example"}},get_mind: function (source) {var df = jm.format.node_tree;var mind = new jm.mind();mind.name = source.meta.name;mind.author = source.meta.author;mind.version = source.meta.version;df._parse(mind, source.data);return mind;},get_data: function (mind) {var df = jm.format.node_tree;var json = {};json.meta = {name: mind.name,author: mind.author,version: mind.version};json.format = 'node_tree';json.data = df._buildnode(mind.root);return json;},_parse: function (mind, node_root) {var df = jm.format.node_tree;var data = df._extract_data(node_root);mind.set_root(node_root.id, node_root.topic, data);if ('children' in node_root) {var children = node_root.children;for (var i = 0; i < children.length; i++) {df._extract_subnode(mind, mind.root, children[i]);}}},_extract_data: function (node_json) {var data = {};for (var k in node_json) {if (k == 'id' || k == 'topic' || k == 'children' || k == 'direction' || k == 'expanded') {continue;}data[k] = node_json[k];}return data;},_extract_subnode: function (mind, node_parent, node_json) {var df = jm.format.node_tree;var data = df._extract_data(node_json);var d = null;if (node_parent.isroot) {d = node_json.direction == 'left' ? jm.direction.left : jm.direction.right;}var node = mind.add_node(node_parent, node_json.id, node_json.topic, data, null, d, node_json.expanded);if ('children' in node_json) {var children = node_json.children;for (var i = 0; i < children.length; i++) {df._extract_subnode(mind, node, children[i]);}}},_buildnode: function (node) {var df = jm.format.node_tree;if (!(node instanceof jm.node)) {return;}var o = {id: node.id,topic: node.topic,expanded: node.expanded};if (!!node.parent && node.parent.isroot) {o.direction = node.direction == jm.direction.left ? 'left' : 'right';}if (node.data != null) {var node_data = node.data;for (var k in node_data) {o[k] = node_data[k];}}var children = node.children;if (children.length > 0) {o.children = [];for (var i = 0; i < children.length; i++) {o.children.push(df._buildnode(children[i]));}}return o;}},node_array: {example: {"meta": {"name": __name__,"author": __author__,"version": __version__},"format": "node_array","data": [{"id": "root", "topic": "jsMind Example", "isroot": true}]},get_mind: function (source) {var df = jm.format.node_array;var mind = new jm.mind();mind.name = source.meta.name;mind.author = source.meta.author;mind.version = source.meta.version;df._parse(mind, source.data);return mind;},get_data: function (mind) {var df = jm.format.node_array;var json = {};json.meta = {name: mind.name,author: mind.author,version: mind.version};json.format = 'node_array';json.data = [];df._array(mind, json.data);return json;},_parse: function (mind, node_array) {var df = jm.format.node_array;var narray = node_array.slice(0);// reverse array for improving looping performancenarray.reverse();var root_id = df._extract_root(mind, narray);if (!!root_id) {df._extract_subnode(mind, root_id, narray);} else {logger.error('root node can not be found');}},_extract_root: function (mind, node_array) {var df = jm.format.node_array;var i = node_array.length;while (i--) {if ('isroot' in node_array[i] && node_array[i].isroot) {var root_json = node_array[i];var data = df._extract_data(root_json);mind.set_root(root_json.id, root_json.topic, data);node_array.splice(i, 1);return root_json.id;}}return null;},_extract_subnode: function (mind, parentid, node_array) {var df = jm.format.node_array;var i = node_array.length;var node_json = null;var data = null;var extract_count = 0;while (i--) {node_json = node_array[i];if (node_json.parentid == parentid) {data = df._extract_data(node_json);var d = null;var node_direction = node_json.direction;if (!!node_direction) {d = node_direction == 'left' ? jm.direction.left : jm.direction.right;}mind.add_node(parentid, node_json.id, node_json.topic, data, null, d, node_json.expanded);node_array.splice(i, 1);extract_count++;var sub_extract_count = df._extract_subnode(mind, node_json.id, node_array);if (sub_extract_count > 0) {// reset loop index after extract subordinate nodei = node_array.length;extract_count += sub_extract_count;}}}return extract_count;},_extract_data: function (node_json) {var data = {};for (var k in node_json) {if (k == 'id' || k == 'topic' || k == 'parentid' || k == 'isroot' || k == 'direction' || k == 'expanded') {continue;}data[k] = node_json[k];}return data;},_array: function (mind, node_array) {var df = jm.format.node_array;df._array_node(mind.root, node_array);},_array_node: function (node, node_array) {var df = jm.format.node_array;if (!(node instanceof jm.node)) {return;}var o = {id: node.id,topic: node.topic,expanded: node.expanded};if (!!node.parent) {o.parentid = node.parent.id;}if (node.isroot) {o.isroot = true;}if (!!node.parent && node.parent.isroot) {o.direction = node.direction == jm.direction.left ? 'left' : 'right';}if (node.data != null) {var node_data = node.data;for (var k in node_data) {o[k] = node_data[k];}}node_array.push(o);var ci = node.children.length;for (var i = 0; i < ci; i++) {df._array_node(node.children[i], node_array);}},},freemind: {example: {"meta": {"name": __name__,"author": __author__,"version": __version__},"format": "freemind","data": "<map version=\"1.0.1\"><node ID=\"root\" TEXT=\"freemind Example\"/></map>"},get_mind: function (source) {var df = jm.format.freemind;var mind = new jm.mind();mind.name = source.meta.name;mind.author = source.meta.author;mind.version = source.meta.version;var xml = source.data;var xml_doc = df._parse_xml(xml);var xml_root = df._find_root(xml_doc);df._load_node(mind, null, xml_root);return mind;},get_data: function (mind) {var df = jm.format.freemind;var json = {};json.meta = {name: mind.name,author: mind.author,version: mind.version};json.format = 'freemind';var xmllines = [];xmllines.push('<map version=\"1.0.1\">');df._buildmap(mind.root, xmllines);xmllines.push('</map>');json.data = xmllines.join(' ');return json;},_parse_xml: function (xml) {var xml_doc = null;if (window.DOMParser) {var parser = new DOMParser();xml_doc = parser.parseFromString(xml, 'text/xml');} else { // Internet Explorerxml_doc = new ActiveXObject('Microsoft.XMLDOM');xml_doc.async = false;xml_doc.loadXML(xml);}return xml_doc;},_find_root: function (xml_doc) {var nodes = xml_doc.childNodes;var node = null;var root = null;var n = null;for (var i = 0; i < nodes.length; i++) {n = nodes[i];if (n.nodeType == 1 && n.tagName == 'map') {node = n;break;}}if (!!node) {var ns = node.childNodes;node = null;for (var i = 0; i < ns.length; i++) {n = ns[i];if (n.nodeType == 1 && n.tagName == 'node') {node = n;break;}}}return node;},_load_node: function (mind, parent_id, xml_node) {var df = jm.format.freemind;var node_id = xml_node.getAttribute('ID');var node_topic = xml_node.getAttribute('TEXT');// look for richcontentif (node_topic == null) {var topic_children = xml_node.childNodes;var topic_child = null;for (var i = 0; i < topic_children.length; i++) {topic_child = topic_children[i];//logger.debug(topic_child.tagName);if (topic_child.nodeType == 1 && topic_child.tagName === 'richcontent') {node_topic = topic_child.textContent;break;}}}var node_data = df._load_attributes(xml_node);var node_expanded = ('expanded' in node_data) ? (node_data.expanded == 'true') : true;delete node_data.expanded;var node_position = xml_node.getAttribute('POSITION');var node_direction = null;if (!!node_position) {node_direction = node_position == 'left' ? jm.direction.left : jm.direction.right;}//logger.debug(node_position +':'+ node_direction);if (!!parent_id) {mind.add_node(parent_id, node_id, node_topic, node_data, null, node_direction, node_expanded);} else {mind.set_root(node_id, node_topic, node_data);}var children = xml_node.childNodes;var child = null;for (var i = 0; i < children.length; i++) {child = children[i];if (child.nodeType == 1 && child.tagName == 'node') {df._load_node(mind, node_id, child);}}},_load_attributes: function (xml_node) {var children = xml_node.childNodes;var attr = null;var attr_data = {};for (var i = 0; i < children.length; i++) {attr = children[i];if (attr.nodeType == 1 && attr.tagName === 'attribute') {attr_data[attr.getAttribute('NAME')] = attr.getAttribute('VALUE');}}return attr_data;},_buildmap: function (node, xmllines) {var df = jm.format.freemind;var pos = null;if (!!node.parent && node.parent.isroot) {pos = node.direction === jm.direction.left ? 'left' : 'right';}xmllines.push('<node');xmllines.push('ID=\"' + node.id + '\"');if (!!pos) {xmllines.push('POSITION=\"' + pos + '\"');}xmllines.push('TEXT=\"' + node.topic + '\">');// store expanded status as an attributexmllines.push('<attribute NAME=\"expanded\" VALUE=\"' + node.expanded + '\"/>');// for attributesvar node_data = node.data;if (node_data != null) {for (var k in node_data) {xmllines.push('<attribute NAME=\"' + k + '\" VALUE=\"' + node_data[k] + '\"/>');}}// for childrenvar children = node.children;for (var i = 0; i < children.length; i++) {df._buildmap(children[i], xmllines);}xmllines.push('</node>');},},};// ============= utility object =============================================jm.util = {is_node: function (node) {return !!node && node instanceof jm.node;},ajax: {_xhr: function () {var xhr = null;if (window.XMLHttpRequest) {xhr = new XMLHttpRequest();} else {try {xhr = new ActiveXObject('Microsoft.XMLHTTP');} catch (e) {}}return xhr;},_eurl: function (url) {return encodeURIComponent(url);},request: function (url, param, method, callback, fail_callback) {var a = jm.util.ajax;var p = null;var tmp_param = [];for (var k in param) {tmp_param.push(a._eurl(k) + '=' + a._eurl(param[k]));}if (tmp_param.length > 0) {p = tmp_param.join('&');}var xhr = a._xhr();if (!xhr) {return;}xhr.onreadystatechange = function () {if (xhr.readyState == 4) {if (xhr.status == 200 || xhr.status == 0) {if (typeof callback === 'function') {var data = jm.util.json.string2json(xhr.responseText);if (data != null) {callback(data);} else {callback(xhr.responseText);}}} else {if (typeof fail_callback === 'function') {fail_callback(xhr);} else {logger.error('xhr request failed.', xhr);}}}}method = method || 'GET';xhr.open(method, url, true);xhr.setRequestHeader('If-Modified-Since', '0');if (method == 'POST') {xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded;charset=utf-8');xhr.send(p);} else {xhr.send();}},get: function (url, callback) {return jm.util.ajax.request(url, {}, 'GET', callback);},post: function (url, param, callback) {return jm.util.ajax.request(url, param, 'POST', callback);}},dom: {//target,eventType,handleradd_event: function (t, e, h) {if (!!t.addEventListener) {t.addEventListener(e, h, false);} else {t.attachEvent('on' + e, h);}}},canvas: {bezierto: function (ctx, x1, y1, x2, y2) {ctx.beginPath();ctx.moveTo(x1, y1);ctx.bezierCurveTo(x1 + (x2 - x1) * 2 / 3, y1, x1, y2, x2, y2);ctx.stroke();},lineto: function (ctx, x1, y1, x2, y2) {ctx.beginPath();ctx.moveTo(x1, y1);ctx.lineTo(x2, y2);ctx.stroke();},clear: function (ctx, x, y, w, h) {ctx.clearRect(x, y, w, h);}},file: {read: function (file_data, fn_callback) {var reader = new FileReader();reader.onload = function () {if (typeof fn_callback === 'function') {fn_callback(this.result, file_data.name);}};reader.readAsText(file_data);},save: function (file_data, type, name) {var blob;if (typeof $w.Blob === 'function') {blob = new Blob([file_data], {type: type});} else {var BlobBuilder = $w.BlobBuilder || $w.MozBlobBuilder || $w.WebKitBlobBuilder || $w.MSBlobBuilder;var bb = new BlobBuilder();bb.append(file_data);blob = bb.getBlob(type);}if (navigator.msSaveBlob) {navigator.msSaveBlob(blob, name);} else {var URL = $w.URL || $w.webkitURL;var bloburl = URL.createObjectURL(blob);var anchor = $c('a');if ('download' in anchor) {anchor.style.visibility = 'hidden';anchor.href = bloburl;anchor.download = name;$d.body.appendChild(anchor);var evt = $d.createEvent('MouseEvents');evt.initEvent('click', true, true);anchor.dispatchEvent(evt);$d.body.removeChild(anchor);} else {location.href = bloburl;}}}},json: {json2string: function (json) {if (!!JSON) {try {var json_str = JSON.stringify(json);return json_str;} catch (e) {logger.warn(e);logger.warn('can not convert to string');return null;}}},string2json: function (json_str) {if (!!JSON) {try {var json = JSON.parse(json_str);return json;} catch (e) {logger.warn(e);logger.warn('can not parse to json');return null;}}},merge: function (b, a) {for (var o in a) {if (o in b) {if (typeof b[o] === 'object' &&Object.prototype.toString.call(b[o]).toLowerCase() == '[object object]' &&!b[o].length) {jm.util.json.merge(b[o], a[o]);} else {b[o] = a[o];}} else {b[o] = a[o];}}return b;}},uuid: {newid: function () {return (new Date().getTime().toString(16) + Math.random().toString(16).substr(2)).substr(2, 16);}},text: {is_empty: function (s) {if (!s) {return true;}return s.replace(/\s*/, '').length == 0;}}};jm.prototype = {init: function () {if (this.inited) {return;}this.inited = true;var opts = this.options;var opts_layout = {mode: opts.mode,hspace: opts.layout.hspace,vspace: opts.layout.vspace,pspace: opts.layout.pspace}var opts_view = {container: opts.container,support_html: opts.support_html,hmargin: opts.view.hmargin,vmargin: opts.view.vmargin,line_width: opts.view.line_width,line_color: opts.view.line_color};// create instance of function providerthis.data = new jm.data_provider(this);this.layout = new jm.layout_provider(this, opts_layout);this.view = new jm.view_provider(this, opts_view);this.shortcut = new jm.shortcut_provider(this, opts.shortcut);this.data.init();this.layout.init();this.view.init();this.shortcut.init();this._event_bind();jm.init_plugins(this);},enable_edit: function () {this.options.editable = true;},disable_edit: function () {this.options.editable = false;},// call enable_event_handle('dblclick')// options are 'mousedown', 'click', 'dblclick'enable_event_handle: function (event_handle) {this.options.default_event_handle['enable_' + event_handle + '_handle'] = true;},// call disable_event_handle('dblclick')// options are 'mousedown', 'click', 'dblclick'disable_event_handle: function (event_handle) {this.options.default_event_handle['enable_' + event_handle + '_handle'] = false;},get_editable: function () {return this.options.editable;},set_theme: function (theme) {var theme_old = this.options.theme;this.options.theme = (!!theme) ? theme : null;if (theme_old != this.options.theme) {this.view.reset_theme();this.view.reset_custom_style();}},_event_bind: function () {this.view.add_event(this, 'mousedown', this.mousedown_handle);this.view.add_event(this, 'click', this.click_handle);this.view.add_event(this, 'dblclick', this.dblclick_handle);},mousedown_handle: function (e) {if (!this.options.default_event_handle['enable_mousedown_handle']) {return;}var element = e.target || event.srcElement;var nodeid = this.view.get_binded_nodeid(element);if (!!nodeid) {this.select_node(nodeid);} else {this.select_clear();}},click_handle: function (e) {if (!this.options.default_event_handle['enable_click_handle']) {return;}var element = e.target || event.srcElement;var isexpander = this.view.is_expander(element);if (isexpander) {var nodeid = this.view.get_binded_nodeid(element);if (!!nodeid) {this.toggle_node(nodeid);}}},dblclick_handle: function (e) {if (!this.options.default_event_handle['enable_dblclick_handle']) {return;}if (this.get_editable()) {var element = e.target || event.srcElement;var nodeid = this.view.get_binded_nodeid(element);if (!!nodeid) {this.begin_edit(nodeid);}}},begin_edit: function (node) {if (!jm.util.is_node(node)) {var the_node = this.get_node(node);if (!the_node) {logger.error('the node[id=' + node + '] can not be found.');return false;} else {return this.begin_edit(the_node);}}if (this.get_editable()) {this.view.edit_node_begin(node);} else {logger.error('fail, this mind map is not editable.');return;}},end_edit: function () {this.view.edit_node_end();},toggle_node: function (node) {if (!jm.util.is_node(node)) {var the_node = this.get_node(node);if (!the_node) {logger.error('the node[id=' + node + '] can not be found.');return;} else {return this.toggle_node(the_node);}}if (node.isroot) {return;}this.view.save_location(node);this.layout.toggle_node(node);this.view.relayout();this.view.restore_location(node);},expand_node: function (node) {if (!jm.util.is_node(node)) {var the_node = this.get_node(node);if (!the_node) {logger.error('the node[id=' + node + '] can not be found.');return;} else {return this.expand_node(the_node);}}if (node.isroot) {return;}this.view.save_location(node);this.layout.expand_node(node);this.view.relayout();this.view.restore_location(node);},collapse_node: function (node) {if (!jm.util.is_node(node)) {var the_node = this.get_node(node);if (!the_node) {logger.error('the node[id=' + node + '] can not be found.');return;} else {return this.collapse_node(the_node);}}if (node.isroot) {return;}this.view.save_location(node);this.layout.collapse_node(node);this.view.relayout();this.view.restore_location(node);},expand_all: function () {this.layout.expand_all();this.view.relayout();},collapse_all: function () {this.layout.collapse_all();this.view.relayout();},expand_to_depth: function (depth) {this.layout.expand_to_depth(depth);this.view.relayout();},_reset: function () {this.view.reset();this.layout.reset();this.data.reset();},_show: function (mind) {var m = mind || jm.format.node_array.example;this.mind = this.data.load(m);if (!this.mind) {logger.error('data.load error');return;} else {logger.debug('data.load ok');}this.view.load();logger.debug('view.load ok');this.layout.layout();logger.debug('layout.layout ok');this.view.show(true);logger.debug('view.show ok');this.invoke_event_handle(jm.event_type.show, {data: [mind]});},show: function (mind) {this._reset();this._show(mind);},get_meta: function () {return {name: this.mind.name,author: this.mind.author,version: this.mind.version};},get_data: function (data_format) {var df = data_format || 'node_tree';return this.data.get_data(df);},get_root: function () {return this.mind.root;},get_node: function (nodeid) {return this.mind.get_node(nodeid);},add_node: function (parent_node, nodeid, topic, data) {if (this.get_editable()) {var node = this.mind.add_node(parent_node, nodeid, topic, data);if (!!node) {this.view.add_node(node);this.layout.layout();this.view.show(false);this.view.reset_node_custom_style(node);this.expand_node(parent_node);this.invoke_event_handle(jm.event_type.edit, {evt: 'add_node',data: [parent_node.id, nodeid, topic, data],node: nodeid});}return node;} else {logger.error('fail, this mind map is not editable');return null;}},insert_node_before: function (node_before, nodeid, topic, data) {if (this.get_editable()) {var beforeid = jm.util.is_node(node_before) ? node_before.id : node_before;var node = this.mind.insert_node_before(node_before, nodeid, topic, data);if (!!node) {this.view.add_node(node);this.layout.layout();this.view.show(false);this.invoke_event_handle(jm.event_type.edit, {evt: 'insert_node_before',data: [beforeid, nodeid, topic, data],node: nodeid});}return node;} else {logger.error('fail, this mind map is not editable');return null;}},insert_node_after: function (node_after, nodeid, topic, data) {if (this.get_editable()) {var afterid = jm.util.is_node(node_after) ? node_after.id : node_after;var node = this.mind.insert_node_after(node_after, nodeid, topic, data);if (!!node) {this.view.add_node(node);this.layout.layout();this.view.show(false);this.invoke_event_handle(jm.event_type.edit, {evt: 'insert_node_after',data: [afterid, nodeid, topic, data],node: nodeid});}return node;} else {logger.error('fail, this mind map is not editable');return null;}},remove_node: function (node) {if (!jm.util.is_node(node)) {var the_node = this.get_node(node);if (!the_node) {logger.error('the node[id=' + node + '] can not be found.');return false;} else {return this.remove_node(the_node);}}if (this.get_editable()) {if (node.isroot) {logger.error('fail, can not remove root node');return false;}var nodeid = node.id;var parentid = node.parent.id;var parent_node = this.get_node(parentid);this.view.save_location(parent_node);this.view.remove_node(node);this.mind.remove_node(node);this.layout.layout();this.view.show(false);this.view.restore_location(parent_node);this.invoke_event_handle(jm.event_type.edit, {evt: 'remove_node', data: [nodeid], node: parentid});return true;} else {logger.error('fail, this mind map is not editable');return false;}},update_node: function (nodeid, topic) {if (this.get_editable()) {if (jm.util.text.is_empty(topic)) {logger.warn('fail, topic can not be empty');return;}var node = this.get_node(nodeid);if (!!node) {if (node.topic === topic) {logger.info('nothing changed');this.view.update_node(node);return;}node.topic = topic;this.view.update_node(node);this.layout.layout();this.view.show(false);this.invoke_event_handle(jm.event_type.edit, {evt: 'update_node',data: [nodeid, topic],node: nodeid});}} else {logger.error('fail, this mind map is not editable');return;}},move_node: function (nodeid, beforeid, parentid, direction) {if (this.get_editable()) {var node = this.mind.move_node(nodeid, beforeid, parentid, direction);if (!!node) {this.view.update_node(node);this.layout.layout();this.view.show(false);this.invoke_event_handle(jm.event_type.edit, {evt: 'move_node',data: [nodeid, beforeid, parentid, direction],node: nodeid});}} else {logger.error('fail, this mind map is not editable');return;}},select_node: function (node) {if (!jm.util.is_node(node)) {var the_node = this.get_node(node);if (!the_node) {logger.error('the node[id=' + node + '] can not be found.');return;} else {return this.select_node(the_node);}}if (!this.layout.is_visible(node)) {return;}this.mind.selected = node;this.view.select_node(node);},get_selected_node: function () {if (!!this.mind) {return this.mind.selected;} else {return null;}},select_clear: function () {if (!!this.mind) {this.mind.selected = null;this.view.select_clear();}},is_node_visible: function (node) {return this.layout.is_visible(node);},find_node_before: function (node) {if (!jm.util.is_node(node)) {var the_node = this.get_node(node);if (!the_node) {logger.error('the node[id=' + node + '] can not be found.');return;} else {return this.find_node_before(the_node);}}if (node.isroot) {return null;}var n = null;if (node.parent.isroot) {var c = node.parent.children;var prev = null;var ni = null;for (var i = 0; i < c.length; i++) {ni = c[i];if (node.direction === ni.direction) {if (node.id === ni.id) {n = prev;}prev = ni;}}} else {n = this.mind.get_node_before(node);}return n;},find_node_after: function (node) {if (!jm.util.is_node(node)) {var the_node = this.get_node(node);if (!the_node) {logger.error('the node[id=' + node + '] can not be found.');return;} else {return this.find_node_after(the_node);}}if (node.isroot) {return null;}var n = null;if (node.parent.isroot) {var c = node.parent.children;var getthis = false;var ni = null;for (var i = 0; i < c.length; i++) {ni = c[i];if (node.direction === ni.direction) {if (getthis) {n = ni;break;}if (node.id === ni.id) {getthis = true;}}}} else {n = this.mind.get_node_after(node);}return n;},set_node_color: function (nodeid, bgcolor, fgcolor) {if (this.get_editable()) {var node = this.mind.get_node(nodeid);if (!!node) {if (!!bgcolor) {node.data['background-color'] = bgcolor;}if (!!fgcolor) {node.data['foreground-color'] = fgcolor;}this.view.reset_node_custom_style(node);}} else {logger.error('fail, this mind map is not editable');return null;}},set_node_font_style: function (nodeid, size, weight, style) {if (this.get_editable()) {var node = this.mind.get_node(nodeid);if (!!node) {if (!!size) {node.data['font-size'] = size;}if (!!weight) {node.data['font-weight'] = weight;}if (!!style) {node.data['font-style'] = style;}this.view.reset_node_custom_style(node);this.view.update_node(node);this.layout.layout();this.view.show(false);}} else {logger.error('fail, this mind map is not editable');return null;}},set_node_background_image: function (nodeid, image, width, height, rotation) {if (this.get_editable()) {var node = this.mind.get_node(nodeid);if (!!node) {if (!!image) {node.data['background-image'] = image;}if (!!width) {node.data['width'] = width;}if (!!height) {node.data['height'] = height;}if (!!rotation) {node.data['background-rotation'] = rotation;}this.view.reset_node_custom_style(node);this.view.update_node(node);this.layout.layout();this.view.show(false);}} else {logger.error('fail, this mind map is not editable');return null;}},set_node_background_rotation: function (nodeid, rotation) {if (this.get_editable()) {var node = this.mind.get_node(nodeid);if (!!node) {if (!node.data['background-image']) {logger.error('fail, only can change rotation angle of node with background image');return null;}node.data['background-rotation'] = rotation;this.view.reset_node_custom_style(node);this.view.update_node(node);this.layout.layout();this.view.show(false);}} else {logger.error('fail, this mind map is not editable');return null;}},resize: function () {this.view.resize();},// callback(type ,data)add_event_listener: function (callback) {if (typeof callback === 'function') {this.event_handles.push(callback);}},invoke_event_handle: function (type, data) {var j = this;$w.setTimeout(function () {j._invoke_event_handle(type, data);}, 0);},_invoke_event_handle: function (type, data) {var l = this.event_handles.length;for (var i = 0; i < l; i++) {this.event_handles[i](type, data);}}};// ============= data provider =============================================jm.data_provider = function (jm) {this.jm = jm;};jm.data_provider.prototype = {init: function () {logger.debug('data.init');},reset: function () {logger.debug('data.reset');},load: function (mind_data) {var df = null;var mind = null;if (typeof mind_data === 'object') {if (!!mind_data.format) {df = mind_data.format;} else {df = 'node_tree';}} else {df = 'freemind';}if (df == 'node_array') {mind = jm.format.node_array.get_mind(mind_data);} else if (df == 'node_tree') {mind = jm.format.node_tree.get_mind(mind_data);} else if (df == 'freemind') {mind = jm.format.freemind.get_mind(mind_data);} else {logger.warn('unsupported format');}return mind;},get_data: function (data_format) {var data = null;if (data_format == 'node_array') {data = jm.format.node_array.get_data(this.jm.mind);} else if (data_format == 'node_tree') {data = jm.format.node_tree.get_data(this.jm.mind);} else if (data_format == 'freemind') {data = jm.format.freemind.get_data(this.jm.mind);} else {logger.error('unsupported ' + data_format + ' format');}return data;},};// ============= layout provider ===========================================jm.layout_provider = function (jm, options) {this.opts = options;this.jm = jm;this.isside = (this.opts.mode == 'side');this.bounds = null;this.cache_valid = false;};jm.layout_provider.prototype = {init: function () {logger.debug('layout.init');},reset: function () {logger.debug('layout.reset');this.bounds = {n: 0, s: 0, w: 0, e: 0};},layout: function () {logger.debug('layout.layout');this.layout_direction();this.layout_offset();},layout_direction: function () {this._layout_direction_root();},_layout_direction_root: function () {var node = this.jm.mind.root;// logger.debug(node);var layout_data = null;if ('layout' in node._data) {layout_data = node._data.layout;} else {layout_data = {};node._data.layout = layout_data;}var children = node.children;var children_count = children.length;layout_data.direction = jm.direction.center;layout_data.side_index = 0;if (this.isside) {var i = children_count;while (i--) {this._layout_direction_side(children[i], jm.direction.right, i);}} else {var i = children_count;var subnode = null;while (i--) {subnode = children[i];if (subnode.direction == jm.direction.left) {this._layout_direction_side(subnode, jm.direction.left, i);} else {this._layout_direction_side(subnode, jm.direction.right, i);}}/*var boundary = Math.ceil(children_count/2);var i = children_count;while(i--){if(i>=boundary){this._layout_direction_side(children[i],jm.direction.left, children_count-i-1);}else{this._layout_direction_side(children[i],jm.direction.right, i);}}*/}},_layout_direction_side: function (node, direction, side_index) {var layout_data = null;if ('layout' in node._data) {layout_data = node._data.layout;} else {layout_data = {};node._data.layout = layout_data;}var children = node.children;var children_count = children.length;layout_data.direction = direction;layout_data.side_index = side_index;var i = children_count;while (i--) {this._layout_direction_side(children[i], direction, i);}},layout_offset: function () {var node = this.jm.mind.root;var layout_data = node._data.layout;layout_data.offset_x = 0;layout_data.offset_y = 0;layout_data.outer_height = 0;var children = node.children;var i = children.length;var left_nodes = [];var right_nodes = [];var subnode = null;while (i--) {subnode = children[i];if (subnode._data.layout.direction == jm.direction.right) {right_nodes.unshift(subnode);} else {left_nodes.unshift(subnode);}}layout_data.left_nodes = left_nodes;layout_data.right_nodes = right_nodes;layout_data.outer_height_left = this._layout_offset_subnodes(left_nodes);layout_data.outer_height_right = this._layout_offset_subnodes(right_nodes);this.bounds.e = node._data.view.width / 2;this.bounds.w = 0 - this.bounds.e;//logger.debug(this.bounds.w);this.bounds.n = 0;this.bounds.s = Math.max(layout_data.outer_height_left, layout_data.outer_height_right);},// layout both the x and y axis_layout_offset_subnodes: function (nodes) {var total_height = 0;var nodes_count = nodes.length;var i = nodes_count;var node = null;var node_outer_height = 0;var layout_data = null;var base_y = 0;var pd = null; // parent._datawhile (i--) {node = nodes[i];layout_data = node._data.layout;if (pd == null) {pd = node.parent._data;}node_outer_height = this._layout_offset_subnodes(node.children);if (!node.expanded) {node_outer_height = 0;this.set_visible(node.children, false);}node_outer_height = Math.max(node._data.view.height, node_outer_height);layout_data.outer_height = node_outer_height;layout_data.offset_y = base_y - node_outer_height / 2;layout_data.offset_x = this.opts.hspace * layout_data.direction + pd.view.width * (pd.layout.direction + layout_data.direction) / 2;if (!node.parent.isroot) {layout_data.offset_x += this.opts.pspace * layout_data.direction;}base_y = base_y - node_outer_height - this.opts.vspace;total_height += node_outer_height;}if (nodes_count > 1) {total_height += this.opts.vspace * (nodes_count - 1);}i = nodes_count;var middle_height = total_height / 2;while (i--) {node = nodes[i];node._data.layout.offset_y += middle_height;}return total_height;},// layout the y axis only, for collapse/expand a node_layout_offset_subnodes_height: function (nodes) {var total_height = 0;var nodes_count = nodes.length;var i = nodes_count;var node = null;var node_outer_height = 0;var layout_data = null;var base_y = 0;var pd = null; // parent._datawhile (i--) {node = nodes[i];layout_data = node._data.layout;if (pd == null) {pd = node.parent._data;}node_outer_height = this._layout_offset_subnodes_height(node.children);if (!node.expanded) {node_outer_height = 0;}node_outer_height = Math.max(node._data.view.height, node_outer_height);layout_data.outer_height = node_outer_height;layout_data.offset_y = base_y - node_outer_height / 2;base_y = base_y - node_outer_height - this.opts.vspace;total_height += node_outer_height;}if (nodes_count > 1) {total_height += this.opts.vspace * (nodes_count - 1);}i = nodes_count;var middle_height = total_height / 2;while (i--) {node = nodes[i];node._data.layout.offset_y += middle_height;//logger.debug(node.topic);//logger.debug(node._data.layout.offset_y);}return total_height;},get_node_offset: function (node) {var layout_data = node._data.layout;var offset_cache = null;if (('_offset_' in layout_data) && this.cache_valid) {offset_cache = layout_data._offset_;} else {offset_cache = {x: -1, y: -1};layout_data._offset_ = offset_cache;}if (offset_cache.x == -1 || offset_cache.y == -1) {var x = layout_data.offset_x;var y = layout_data.offset_y;if (!node.isroot) {var offset_p = this.get_node_offset(node.parent);x += offset_p.x;y += offset_p.y;}offset_cache.x = x;offset_cache.y = y;}return offset_cache;},get_node_point: function (node) {var view_data = node._data.view;var offset_p = this.get_node_offset(node);//logger.debug(offset_p);var p = {};p.x = offset_p.x + view_data.width * (node._data.layout.direction - 1) / 2;p.y = offset_p.y - view_data.height / 2;//logger.debug(p);return p;},get_node_point_in: function (node) {var p = this.get_node_offset(node);return p;},get_node_point_out: function (node) {var layout_data = node._data.layout;var pout_cache = null;if (('_pout_' in layout_data) && this.cache_valid) {pout_cache = layout_data._pout_;} else {pout_cache = {x: -1, y: -1};layout_data._pout_ = pout_cache;}if (pout_cache.x == -1 || pout_cache.y == -1) {if (node.isroot) {pout_cache.x = 0;pout_cache.y = 0;} else {var view_data = node._data.view;var offset_p = this.get_node_offset(node);pout_cache.x = offset_p.x + (view_data.width + this.opts.pspace) * node._data.layout.direction;pout_cache.y = offset_p.y;//logger.debug('pout');//logger.debug(pout_cache);}}return pout_cache;},get_expander_point: function (node) {var p = this.get_node_point_out(node);var ex_p = {};if (node._data.layout.direction == jm.direction.right) {ex_p.x = p.x - this.opts.pspace;} else {ex_p.x = p.x;}ex_p.y = p.y - Math.ceil(this.opts.pspace / 2);return ex_p;},get_min_size: function () {var nodes = this.jm.mind.nodes;var node = null;var pout = null;for (var nodeid in nodes) {node = nodes[nodeid];pout = this.get_node_point_out(node);//logger.debug(pout.x);if (pout.x > this.bounds.e) {this.bounds.e = pout.x;}if (pout.x < this.bounds.w) {this.bounds.w = pout.x;}}return {w: this.bounds.e - this.bounds.w,h: this.bounds.s - this.bounds.n}},toggle_node: function (node) {if (node.isroot) {return;}if (node.expanded) {this.collapse_node(node);} else {this.expand_node(node);}},expand_node: function (node) {node.expanded = true;this.part_layout(node);this.set_visible(node.children, true);},collapse_node: function (node) {node.expanded = false;this.part_layout(node);this.set_visible(node.children, false);},expand_all: function () {var nodes = this.jm.mind.nodes;var c = 0;var node;for (var nodeid in nodes) {node = nodes[nodeid];if (!node.expanded) {node.expanded = true;c++;}}if (c > 0) {var root = this.jm.mind.root;this.part_layout(root);this.set_visible(root.children, true);}},collapse_all: function () {var nodes = this.jm.mind.nodes;var c = 0;var node;for (var nodeid in nodes) {node = nodes[nodeid];if (node.expanded && !node.isroot) {node.expanded = falsec++;}}if (c > 0) {var root = this.jm.mind.root;this.part_layout(root);this.set_visible(root.children, true);}},expand_to_depth: function (target_depth, curr_nodes, curr_depth) {if (target_depth < 1) {return;}var nodes = curr_nodes || this.jm.mind.root.children;var depth = curr_depth || 1;var i = nodes.length;var node = null;while (i--) {node = nodes[i];if (depth < target_depth) {if (!node.expanded) {this.expand_node(node);}this.expand_to_depth(target_depth, node.children, depth + 1);}if (depth == target_depth) {if (node.expanded) {this.collapse_node(node);}}}},part_layout: function (node) {var root = this.jm.mind.root;if (!!root) {var root_layout_data = root._data.layout;if (node.isroot) {root_layout_data.outer_height_right = this._layout_offset_subnodes_height(root_layout_data.right_nodes);root_layout_data.outer_height_left = this._layout_offset_subnodes_height(root_layout_data.left_nodes);} else {if (node._data.layout.direction == jm.direction.right) {root_layout_data.outer_height_right = this._layout_offset_subnodes_height(root_layout_data.right_nodes);} else {root_layout_data.outer_height_left = this._layout_offset_subnodes_height(root_layout_data.left_nodes);}}this.bounds.s = Math.max(root_layout_data.outer_height_left, root_layout_data.outer_height_right);this.cache_valid = false;} else {logger.warn('can not found root node');}},set_visible: function (nodes, visible) {var i = nodes.length;var node = null;var layout_data = null;while (i--) {node = nodes[i];layout_data = node._data.layout;if (node.expanded) {this.set_visible(node.children, visible);} else {this.set_visible(node.children, false);}if (!node.isroot) {node._data.layout.visible = visible;}}},is_expand: function (node) {return node.expanded;},is_visible: function (node) {var layout_data = node._data.layout;if (('visible' in layout_data) && !layout_data.visible) {return false;} else {return true;}},};// view providerjm.view_provider = function (jm, options) {this.opts = options;this.jm = jm;this.layout = jm.layout;this.container = null;this.e_panel = null;this.e_nodes = null;this.e_canvas = null;this.canvas_ctx = null;this.size = {w: 0, h: 0};this.selected_node = null;this.editing_node = null;};jm.view_provider.prototype = {init: function () {logger.debug('view.init');this.container = $i(this.opts.container) ? this.opts.container : $g(this.opts.container);if (!this.container) {logger.error('the options.view.container was not be found in dom');return;}this.e_panel = $c('div');this.e_canvas = $c('canvas');this.e_nodes = $c('jmnodes');this.e_editor = $c('input');this.e_panel.className = 'jsmind-inner';this.e_panel.appendChild(this.e_canvas);this.e_panel.appendChild(this.e_nodes);this.e_editor.className = 'jsmind-editor';this.e_editor.type = 'text';this.actualZoom = 1;this.zoomStep = 0.1;this.minZoom = 0.5;this.maxZoom = 2;var v = this;jm.util.dom.add_event(this.e_editor, 'keydown', function (e) {var evt = e || event;if (evt.keyCode == 13) {v.edit_node_end();evt.stopPropagation();}});jm.util.dom.add_event(this.e_editor, 'blur', function (e) {v.edit_node_end();});this.container.appendChild(this.e_panel);this.init_canvas();},add_event: function (obj, event_name, event_handle) {jm.util.dom.add_event(this.e_nodes, event_name, function (e) {var evt = e || event;event_handle.call(obj, evt);});},get_binded_nodeid: function (element) {if (element == null) {return null;}var tagName = element.tagName.toLowerCase();if (tagName == 'jmnodes' || tagName == 'body' || tagName == 'html') {return null;}if (tagName == 'jmnode' || tagName == 'jmexpander') {return element.getAttribute('nodeid');} else {return this.get_binded_nodeid(element.parentElement);}},is_expander: function (element) {return (element.tagName.toLowerCase() == 'jmexpander');},reset: function () {logger.debug('view.reset');this.selected_node = null;this.clear_lines();this.clear_nodes();this.reset_theme();},reset_theme: function () {var theme_name = this.jm.options.theme;if (!!theme_name) {this.e_nodes.className = 'theme-' + theme_name;} else {this.e_nodes.className = '';}},reset_custom_style: function () {var nodes = this.jm.mind.nodes;for (var nodeid in nodes) {this.reset_node_custom_style(nodes[nodeid]);}},load: function () {logger.debug('view.load');this.init_nodes();},expand_size: function () {var min_size = this.layout.get_min_size();var min_width = min_size.w + this.opts.hmargin * 2;var min_height = min_size.h + this.opts.vmargin * 2;var client_w = this.e_panel.clientWidth;var client_h = this.e_panel.clientHeight;if (client_w < min_width) {client_w = min_width;}if (client_h < min_height) {client_h = min_height;}this.size.w = client_w;this.size.h = client_h;},init_canvas: function () {var ctx = this.e_canvas.getContext('2d');this.canvas_ctx = ctx;},init_nodes_size: function (node) {var view_data = node._data.view;view_data.width = view_data.element.clientWidth;view_data.height = view_data.element.clientHeight;},init_nodes: function () {var nodes = this.jm.mind.nodes;var doc_frag = $d.createDocumentFragment();for (var nodeid in nodes) {this.create_node_element(nodes[nodeid], doc_frag);}this.e_nodes.appendChild(doc_frag);for (var nodeid in nodes) {this.init_nodes_size(nodes[nodeid]);}},add_node: function (node) {this.create_node_element(node, this.e_nodes);this.init_nodes_size(node);},create_node_element: function (node, parent_node) {var view_data = null;if ('view' in node._data) {view_data = node._data.view;} else {view_data = {};node._data.view = view_data;}var d = $c('jmnode');if (node.isroot) {d.className = 'root';} else {var d_e = $c('jmexpander');$t(d_e, '');d_e.setAttribute('nodeid', node.id);d_e.style.visibility = 'hidden';parent_node.appendChild(d_e);view_data.expander = d_e;}if (!!node.topic) {if (this.opts.support_html) {$h(d, node.topic);} else {$t(d, node.topic);}}d.setAttribute('nodeid', node.id);d.style.visibility = 'hidden';this._reset_node_custom_style(d, node.data);parent_node.appendChild(d);view_data.element = d;},remove_node: function (node) {if (this.selected_node != null && this.selected_node.id == node.id) {this.selected_node = null;}if (this.editing_node != null && this.editing_node.id == node.id) {node._data.view.element.removeChild(this.e_editor);this.editing_node = null;}var children = node.children;var i = children.length;while (i--) {this.remove_node(children[i]);}if (node._data.view) {var element = node._data.view.element;var expander = node._data.view.expander;this.e_nodes.removeChild(element);this.e_nodes.removeChild(expander);node._data.view.element = null;node._data.view.expander = null;}},update_node: function (node) {var view_data = node._data.view;var element = view_data.element;if (!!node.topic) {if (this.opts.support_html) {$h(element, node.topic);} else {$t(element, node.topic);}}view_data.width = element.clientWidth;view_data.height = element.clientHeight;},select_node: function (node) {if (!!this.selected_node) {this.selected_node._data.view.element.className =this.selected_node._data.view.element.className.replace(/\s*selected\b/i, '');this.reset_node_custom_style(this.selected_node);}if (!!node) {this.selected_node = node;node._data.view.element.className += ' selected';this.clear_node_custom_style(node);}},select_clear: function () {this.select_node(null);},get_editing_node: function () {return this.editing_node;},is_editing: function () {return (!!this.editing_node);},edit_node_begin: function (node) {if (!node.topic) {logger.warn("don't edit image nodes");return;}if (this.editing_node != null) {this.edit_node_end();}this.editing_node = node;var view_data = node._data.view;var element = view_data.element;var topic = node.topic;var ncs = getComputedStyle(element);this.e_editor.value = topic;this.e_editor.style.width = (element.clientWidth - parseInt(ncs.getPropertyValue('padding-left')) - parseInt(ncs.getPropertyValue('padding-right'))) + 'px';element.innerHTML = '';element.appendChild(this.e_editor);element.style.zIndex = 5;this.e_editor.focus();this.e_editor.select();},edit_node_end: function () {if (this.editing_node != null) {var node = this.editing_node;this.editing_node = null;var view_data = node._data.view;var element = view_data.element;var topic = this.e_editor.value;element.style.zIndex = 'auto';element.removeChild(this.e_editor);if (jm.util.text.is_empty(topic) || node.topic === topic) {if (this.opts.support_html) {$h(element, node.topic);} else {$t(element, node.topic);}} else {this.jm.update_node(node.id, topic);}}},get_view_offset: function () {var bounds = this.layout.bounds;var _x = (this.size.w - bounds.e - bounds.w) / 2;var _y = this.size.h / 2;return {x: _x, y: _y};},resize: function () {this.e_canvas.width = 1;this.e_canvas.height = 1;this.e_nodes.style.width = '1px';this.e_nodes.style.height = '1px';this.expand_size();this._show();},_show: function () {this.e_canvas.width = this.size.w;this.e_canvas.height = this.size.h;this.e_nodes.style.width = this.size.w + 'px';this.e_nodes.style.height = this.size.h + 'px';this.show_nodes();this.show_lines();//this.layout.cache_valid = true;this.jm.invoke_event_handle(jm.event_type.resize, {data: []});},zoomIn: function () {return this.setZoom(this.actualZoom + this.zoomStep);},zoomOut: function () {return this.setZoom(this.actualZoom - this.zoomStep);},setZoom: function (zoom) {if ((zoom < this.minZoom) || (zoom > this.maxZoom)) {return false;}this.actualZoom = zoom;for (var i = 0; i < this.e_panel.children.length; i++) {this.e_panel.children[i].style.transform = 'scale(' + zoom + ')';};this.show(true);return true;},_center_root: function () {// center root nodevar outer_w = this.e_panel.clientWidth;var outer_h = this.e_panel.clientHeight;if (this.size.w > outer_w) {var _offset = this.get_view_offset();this.e_panel.scrollLeft = _offset.x - outer_w / 2;}if (this.size.h > outer_h) {this.e_panel.scrollTop = (this.size.h - outer_h) / 2;}},show: function (keep_center) {logger.debug('view.show');this.expand_size();this._show();if (!!keep_center) {this._center_root();}},relayout: function () {this.expand_size();this._show();},save_location: function (node) {var vd = node._data.view;vd._saved_location = {x: parseInt(vd.element.style.left) - this.e_panel.scrollLeft,y: parseInt(vd.element.style.top) - this.e_panel.scrollTop,};},restore_location: function (node) {var vd = node._data.view;this.e_panel.scrollLeft = parseInt(vd.element.style.left) - vd._saved_location.x;this.e_panel.scrollTop = parseInt(vd.element.style.top) - vd._saved_location.y;},clear_nodes: function () {var mind = this.jm.mind;if (mind == null) {return;}var nodes = mind.nodes;var node = null;for (var nodeid in nodes) {node = nodes[nodeid];node._data.view.element = null;node._data.view.expander = null;}this.e_nodes.innerHTML = '';},show_nodes: function () {var nodes = this.jm.mind.nodes;var node = null;var node_element = null;var expander = null;var p = null;var p_expander = null;//关闭子节点按钮var expander_text = '';var view_data = null;var _offset = this.get_view_offset();for (var nodeid in nodes) {node = nodes[nodeid];view_data = node._data.view;node_element = view_data.element;expander = view_data.expander;if (!this.layout.is_visible(node)) {node_element.style.display = 'none';expander.style.display = 'none';continue;}this.reset_node_custom_style(node);p = this.layout.get_node_point(node);view_data.abs_x = _offset.x + p.x;view_data.abs_y = _offset.y + p.y;node_element.style.left = (_offset.x + p.x) + 'px';node_element.style.top = (_offset.y + p.y) + 'px';node_element.style.display = '';node_element.style.visibility = 'visible';if (!node.isroot && node.children.length > 0) {//关闭子节点按钮expander_text = node.expanded ? '㊀' : ' ㊉';p_expander = this.layout.get_expander_point(node);expander.style.left = (_offset.x + p_expander.x) + 'px';expander.style.top = (_offset.y + p_expander.y) + 'px';expander.style.display = '';expander.style.visibility = 'visible';$t(expander, expander_text);}// hide expander while all children have been removedif (!node.isroot && node.children.length == 0) {expander.style.display = 'none';expander.style.visibility = 'hidden';}}},reset_node_custom_style: function (node) {this._reset_node_custom_style(node._data.view.element, node.data);},_reset_node_custom_style: function (node_element, node_data) {if ('background-color' in node_data) {node_element.style.backgroundColor = node_data['background-color'];}if ('foreground-color' in node_data) {node_element.style.color = node_data['foreground-color'];}if ('width' in node_data) {node_element.style.width = node_data['width'] + 'px';}if ('height' in node_data) {node_element.style.height = node_data['height'] + 'px';}if ('font-size' in node_data) {node_element.style.fontSize = node_data['font-size'] + 'px';}if ('font-weight' in node_data) {node_element.style.fontWeight = node_data['font-weight'];}if ('font-style' in node_data) {node_element.style.fontStyle = node_data['font-style'];}if ('background-image' in node_data) {var backgroundImage = node_data['background-image'];if (backgroundImage.startsWith('data') && node_data['width'] && node_data['height']) {var img = new Image();img.onload = function () {var c = $c('canvas');c.width = node_element.clientWidth;c.height = node_element.clientHeight;var img = this;if (c.getContext) {var ctx = c.getContext('2d');ctx.drawImage(img, 2, 2, node_element.clientWidth, node_element.clientHeight);var scaledImageData = c.toDataURL();node_element.style.backgroundImage = 'url(' + scaledImageData + ')';}};img.src = backgroundImage;} else {node_element.style.backgroundImage = 'url(' + backgroundImage + ')';}node_element.style.backgroundSize = '99%';if ('background-rotation' in node_data) {node_element.style.transform = 'rotate(' + node_data['background-rotation'] + 'deg)';}}},clear_node_custom_style: function (node) {var node_element = node._data.view.element;node_element.style.backgroundColor = "";node_element.style.color = "";},clear_lines: function (canvas_ctx) {var ctx = canvas_ctx || this.canvas_ctx;jm.util.canvas.clear(ctx, 0, 0, this.size.w, this.size.h);},show_lines: function (canvas_ctx) {this.clear_lines(canvas_ctx);var nodes = this.jm.mind.nodes;var node = null;var pin = null;var pout = null;var _offset = this.get_view_offset();for (var nodeid in nodes) {node = nodes[nodeid];if (!!node.isroot) {continue;}if (('visible' in node._data.layout) && !node._data.layout.visible) {continue;}pin = this.layout.get_node_point_in(node);pout = this.layout.get_node_point_out(node.parent);this.draw_line(pout, pin, _offset, canvas_ctx);}},//绘制连接线draw_line: function (pin, pout, offset, canvas_ctx) {var ctx = canvas_ctx || this.canvas_ctx;ctx.strokeStyle = this.opts.line_color;ctx.lineWidth = this.opts.line_width;ctx.lineCap = 'round';//画折线ctx.moveTo(pin.x + offset.x, pin.y + offset.y);       //设置起点状态ctx.lineTo(pin.x + offset.x, pout.y + offset.y);       //设置末端状态ctx.moveTo(pin.x + offset.x, pout.y + offset.y);       //设置起点状态ctx.lineTo(pout.x + offset.x, pout.y + offset.y);       //设置末端状态ctx.lineWidth = 2;          //设置线宽状态ctx.stroke();               //进行绘制//画贝塞尔曲线// jm.util.canvas.bezierto(//     ctx,//     pin.x + offset.x,//     pin.y + offset.y,//     pout.x + offset.x,//     pout.y + offset.y);},};// shortcut providerjm.shortcut_provider = function (jm, options) {this.jm = jm;this.opts = options;this.mapping = options.mapping;this.handles = options.handles;this._mapping = {};};jm.shortcut_provider.prototype = {init: function () {jm.util.dom.add_event($d, 'keydown', this.handler.bind(this));this.handles['addchild'] = this.handle_addchild;this.handles['addbrother'] = this.handle_addbrother;this.handles['editnode'] = this.handle_editnode;this.handles['delnode'] = this.handle_delnode;this.handles['toggle'] = this.handle_toggle;this.handles['up'] = this.handle_up;this.handles['down'] = this.handle_down;this.handles['left'] = this.handle_left;this.handles['right'] = this.handle_right;for (var handle in this.mapping) {if (!!this.mapping[handle] && (handle in this.handles)) {this._mapping[this.mapping[handle]] = this.handles[handle];}}},enable_shortcut: function () {this.opts.enable = true;},disable_shortcut: function () {this.opts.enable = false;},handler: function (e) {if (this.jm.view.is_editing()) {return;}var evt = e || event;if (!this.opts.enable) {return true;}var kc = evt.keyCode;if (kc in this._mapping) {this._mapping[kc].call(this, this.jm, e);}},handle_addchild: function (_jm, e) {var selected_node = _jm.get_selected_node();if (!!selected_node) {var nodeid = jm.util.uuid.newid();var node = _jm.add_node(selected_node, nodeid, 'New Node');if (!!node) {_jm.select_node(nodeid);_jm.begin_edit(nodeid);}}},handle_addbrother: function (_jm, e) {var selected_node = _jm.get_selected_node();if (!!selected_node && !selected_node.isroot) {var nodeid = jm.util.uuid.newid();var node = _jm.insert_node_after(selected_node, nodeid, 'New Node');if (!!node) {_jm.select_node(nodeid);_jm.begin_edit(nodeid);}}},handle_editnode: function (_jm, e) {var selected_node = _jm.get_selected_node();if (!!selected_node) {_jm.begin_edit(selected_node);}},handle_delnode: function (_jm, e) {var selected_node = _jm.get_selected_node();if (!!selected_node && !selected_node.isroot) {_jm.select_node(selected_node.parent);_jm.remove_node(selected_node);}},handle_toggle: function (_jm, e) {var evt = e || event;var selected_node = _jm.get_selected_node();if (!!selected_node) {_jm.toggle_node(selected_node.id);evt.stopPropagation();evt.preventDefault();}},handle_up: function (_jm, e) {var evt = e || event;var selected_node = _jm.get_selected_node();if (!!selected_node) {var up_node = _jm.find_node_before(selected_node);if (!up_node) {var np = _jm.find_node_before(selected_node.parent);if (!!np && np.children.length > 0) {up_node = np.children[np.children.length - 1];}}if (!!up_node) {_jm.select_node(up_node);}evt.stopPropagation();evt.preventDefault();}},handle_down: function (_jm, e) {var evt = e || event;var selected_node = _jm.get_selected_node();if (!!selected_node) {var down_node = _jm.find_node_after(selected_node);if (!down_node) {var np = _jm.find_node_after(selected_node.parent);if (!!np && np.children.length > 0) {down_node = np.children[0];}}if (!!down_node) {_jm.select_node(down_node);}evt.stopPropagation();evt.preventDefault();}},handle_left: function (_jm, e) {this._handle_direction(_jm, e, jm.direction.left);},handle_right: function (_jm, e) {this._handle_direction(_jm, e, jm.direction.right);},_handle_direction: function (_jm, e, d) {var evt = e || event;var selected_node = _jm.get_selected_node();var node = null;if (!!selected_node) {if (selected_node.isroot) {var c = selected_node.children;var children = [];for (var i = 0; i < c.length; i++) {if (c[i].direction === d) {children.push(i)}}node = c[children[Math.floor((children.length - 1) / 2)]];} else if (selected_node.direction === d) {var children = selected_node.children;var childrencount = children.length;if (childrencount > 0) {node = children[Math.floor((childrencount - 1) / 2)]}} else {node = selected_node.parent;}if (!!node) {_jm.select_node(node);}evt.stopPropagation();evt.preventDefault();}},};// pluginjm.plugin = function (name, init) {this.name = name;this.init = init;};jm.plugins = [];jm.register_plugin = function (plugin) {if (plugin instanceof jm.plugin) {jm.plugins.push(plugin);}};jm.init_plugins = function (sender) {$w.setTimeout(function () {jm._init_plugins(sender);}, 0);};jm._init_plugins = function (sender) {var l = jm.plugins.length;var fn_init = null;for (var i = 0; i < l; i++) {fn_init = jm.plugins[i].init;if (typeof fn_init === 'function') {fn_init(sender);}}};// quick wayjm.show = function (options, mind) {var _jm = new jm(options);_jm.show(mind);return _jm;};// export jsmindif (typeof module !== 'undefined' && typeof exports === 'object') {module.exports = jm;} else if (typeof define === 'function' && (define.amd || define.cmd)) {define(function () {return jm;});} else {$w[__name__] = jm;}
})(typeof window !== 'undefined' ? window : global);

5.mind.js


import { ElMessage } from "element-plus";
let name = ''
const handleClick = function (checked, name,id,topic_en) {console.log('###############勾选结点',checked, name,id,topic_en); window.name = nameif(checked===true){window.checkedList.add(topic_en)}else{window.checkedList.delete(topic_en)}   // window.checkedList.delete(currentPath.split(','))//  getPathById(window.uncheckedData, topic_en, res => {//     let path = res.join(',');
//      window.targetData.push( path.split(','));
//   });console.log('###############目标结点',window.targetData  ); console.log('############window.checkedList',window.checkedList);
};
// const getNodePath=()=>{//   let temp=Array.from( window.checkedList);
//   temp.forEach((item)=>{//    getPathById(window.uncheckedData, item, res => {//     let path = res.join(',');
//      window.targetData.push( path.split(','));//     //  let currentPath= res.join(',');//       //  console.log('###############目标结点',currentPath)
//       //  window.checkedList.add( currentPath.split(','))//    });
//   })
// }
// //根据topic_en,计算树结构路径点
// const getPathById=(catalog, topic_en, callback)=>{//   //定义变量保存当前结果路径
//   let nodepath=[];
//   try {//     function getNodePath(node) {//       // temppath.push(node.id);
//       nodepath.push(node.topic_en);
//       //找到符合条件的节点,通过throw终止掉递归
//       if (node.topic_en === topic_en) {//         throw ('');
//       }
//       if (node.children && node.children.length > 0) {//         for (let i = 0; i < node.children.length; i++) {//           getNodePath(node.children[i]);
//         }
//         //当前节点的子节点遍历完依旧没找到,则删除路径中的该节点
//       nodepath.pop();//       } else {//         //找到叶子节点时,删除路径当中的该叶子节点
//         nodepath.pop();
//       }
//     }
//     getNodePath(catalog);
//   } catch (e) {//     let result =nodepath;
//     callback(result);
//   }
// }
const handleInput=function(value, name,id){console.log('编辑权重',value, name,id);window.name = nameconsole.log("metaData",window.metaData);if(!(/^[+]{0,1}(\d+)$|^[+]{0,1}(\d+\.\d+)$/).test(value)){// this.$message({//   type: "error",//   message: "权重值不能为负数!",//   duration: 2000,// });ElMessage({message: "权重值不能为负数!",type: "warning",});console.log('负数');return;}DFS(window.metaData).forEach((item)=>{if(item.id===id ){item.number=[value]}})console.log('修改后数据',window.metaData);
}
const DFS = (node, nodeList = []) => {//node不能为nullif (node !== null) {nodeList.push(node)let children = node.children || []//如果children.length存在for (let i = 0; i < children.length; i++) {//递归调用DFS(children[i], nodeList)}}// console.log('nodeList',nodeList);return nodeList
}  

6. test.vue

<template><div class="test"><minder :data="mindData" :type="type"></minder></div>
</template><script lang="ts">
import { defineComponent, reactive, toRefs } from "vue";
import Minder from "@/components/minder/DataMind.vue";export default defineComponent({name: "test",components: { Minder },setup() {const state = reactive({type: "check", //type:defalut,check,label,label2,inputmindData: (window as any).mindData,});const number: number | number[] =state.type === "label2" ? [98, 65, 21, 78] : [13]; //[98标签1,65标签2,方差,均值]const initData = () => {(window as any).mindData = {id: "root",topic: "根节点名字",number: [88],children: [{id: "easy",topic: "规章制度",children: [{ id: "easy1", topic: "请休假制度" },{ id: "easy2", topic: "考勤制度" },],},{id: "open",topic: "岗位职责",children: [{id: "open1",topic: "人事部职责",children: [{ id: "open1-1", topic: "行政管理" },{ id: "open1-2", topic: "人事管理" },],},{id: "open2",topic: "信息部职责",children: [{ id: "open2-1", topic: "信息安全" },{ id: "open2-2", topic: "信息排查" },{ id: "open2-3", topic: "信息汇总" },{ id: "open2-4", topic: "ERP" },],},{id: "open3",topic: "生产车间",children: [{ id: "open3-1", topic: "安全制度" },{ id: "open3-2", topic: "车间操作手册" },],},],},{id: "powerful",topic: "员工福利",number,children: [{ id: "powerful1", topic: "雪天", tip: "3366" },{ id: "powerful2", topic: "年假", tip: "98999" },{id: "powerful3",topic: "法定节假日",number,},{ id: "powerful4", topic: "生日祝福" },{id: "powerful5",topic: "成长与进步",children: [{ id: "powerful5-1", topic: "员工培训" }],},],},],};};setTimeout(() => {initData();state.mindData = (window as any).mindData;}, 100);return {...toRefs(state),};},mounted() {function generateParenthesis(n: number): string[] {}},
});
</script>
<style lang="scss" scoped>
.test {width: 100%;height: 100%;padding: 20px;
}
</style>

7. 运行效果

js+css改造jsmind实现思维导图 | 树状图相关推荐

  1. html树状图右侧_树状图及制作方法(Excel 2016/Excel 2013)

    ↑↑↑关注ExcelEasy,让Excel更简单 树状图是一种展示层次结构数据的图表,可以很好的揭示各类别数据的比例关系及类别内数据的组成结构.今天为大家详细介绍一下树状图的制作方法 树状图在Exce ...

  2. QC(质量控制)图,新旧七图汇总连载(什么是因果图、树状图、直方图……)

    做报告.总结.计划时,少不了图示,一些常用的图示起源于QC(质量控制)图,有的简单,有的在画法上还是要注意些含义的.下面先简单汇总下这些图,后面的博客连载,详细介绍这些图. 新旧七种工具都是由日本人总 ...

  3. 在vue中使用jsmind生成思维导图

    在vue中使用jsmind生成思维导图 前景: 项目中有涉及到多层级的数据结构,思维导图的方式更方便查看数据的关系 技术实现:jsmind 实现效果: 安装 npm i jsmind 代码 <t ...

  4. html树状图在线画板,五款在线思维导图工具,总有一款适合你

    原标题:五款在线思维导图工具,总有一款适合你 思维导图是表达发散性思维的有效图形思维工具,通过一些主要的关键词,用非线性的方式展现出来.思维导图的真正用处不是让你能直接获得多少多少的好处,它更多的,还 ...

  5. 画出计算机系统构成的树状图,如何绘制树状层次结构的树状思维导图?

    树状图,(又为树形图)因其外观像倒过来的树的样子,所以命名树状图.树形图是数据树的图形表示形式,以父子层次结构来组织对象.是枚举法的一种表达方式.初中学生学习概率时通常会要画的树状图.学会分析一件事物 ...

  6. 超详细的html+css基础知识树状图~HTML标签

    前言 学习任何新知识,最重要的永远都是搭建属于自己的知识框架,随后学习的细碎知识点往框架里面填入,最后形成一棵属于自己的知识大树.本系列的博客专注更新总结好的思维导图,希望可以帮助大家快速理清知识结构 ...

  7. 用D3.js画树状图

    做项目遇到一个需求,将具有层级关系的词语用树状图的形式展示它们之间的关系,像这样: 或者是这样: 上面的图片只是样例,跟我下面的代码里面用的数据不同 网上有很多这种数据可视化展示的js控件,我这里选择 ...

  8. Plotly.js使用详细介绍(折线图、饼状图、点图、水平条形图、桑基图、树状图、等值线图)

    目录 0 写在前面 1 HTML代码 2 折线图 2.1 基本折线图 2.2 复杂折线图 2.2.1 轨迹 2.2.2 布局 3 饼状图 3.1 基本饼状图 3.2 饼图子图 3.3 甜甜圈图 4 点 ...

  9. d3.js v3版本实现-树状图

    参考的例子:http://bl.ocks.org/robschmuecker/7880033 一.为什么选择d3.js 二.d3.js概述 三:树状图实现 1.创建svg 2.在svg元素里面画一个g ...

  10. HTML+CSS自定义树状图

    HTML+CSS自定义树状图 主体部分 css部分 主体部分 <div class="test"><ul class="domtree"> ...

最新文章

  1. 在人工智能领域,人工智能机器无法如人一样理解常识知识
  2. 自己动手写C语言编译器(暂停)
  3. 服务器缓存策略(304)
  4. 【原创】6年测试经验,总结一下我心中的开发流程
  5. mysql查询时有两条一模一样的结果应该只显示一条
  6. 一步步在Kubernetes里运行Web应用
  7. IO概述、异常、File文件类_DAY19
  8. leetcode 91. 解码方法(dp)
  9. 数据库表名大小写_某教程学习笔记(一):09、MYSQL数据库漏洞
  10. 爱因斯坦和高中几何问题
  11. UC神马数据采集api
  12. 在Windows中测试c语言单个函数运行时间方法
  13. python中update是啥意思_python中update的基本使用方法详解
  14. matlab如何求空间一点到直线距离,空间点到直线距离怎么求
  15. fences卸载_WIN10专业版彻底删除fences的技巧
  16. LRc2022 M1原生支持功能介绍,Lightroom Classic 2022 Mac M1专用 ,解决lr闪退打不开卡死等一系列问题
  17. 模仿电影中黑客电脑界面,CMD装逼代码
  18. 如果要你向别人推荐电影,你最先想到的是那些呢?
  19. 稀疏矩阵的加法(用十字链表实现A=A+B)
  20. Android - Audio - Qcom平台 - hac器件bring up

热门文章

  1. 有道词典java下载电脑版下载不了_网易有道词典电脑版下载
  2. python爬取糗百第一页的笑话
  3. 企业网络管理利器-SpiceWorks(1)
  4. 无线传感网学习笔记(6)—— S-MAC协议 和 Z-MAC协议
  5. 颜色对照表(三)(16进制、RGB、CMYK、HSV、中英文名)
  6. (6)微信UI自动化-搜索指定联系人(C#)
  7. MQ消息队列的优缺点介绍以及对比选型
  8. 22 个最常用的Python包
  9. MacOS罗技鼠标定义的功能键经常失灵
  10. python数据类型