文章 Michael Lei · 九月 13, 2022 12m read

使用 Globals存储思维导图

  

Globals是InterSystems IRIS的数据持久性的核心。它很灵活,允许存储JSON文档、关系数据、面向对象的数据、OLAP立方体和自定义数据模型,例如思维导图。要了解如何使用globals来存储、删除和获取思维导图数据,请遵循以下步骤:

1. 把repo Clone/git到任意本地目录

$ git clone https://github.com/yurimarx/global-mindmap.git

2. 在该目录下打开Docker 终端并执行:

$ docker-compose build

3. 启动 IRIS 容器:

$ docker-compose up -d

4. 访问 http://localhost:3000 来使用思维导图的前端并创建类似以上的思维导图

本例子的源代码

存储数据 (更多请访问: https://www.npmjs.com/package/mind-elixir):

{topic: 'node topic',id: 'bd1c24420cd2c2f5',style: {fontSize: '32',color: '#3298db',background: '#ecf0f1'},parent: null,tags: ['Tag'],icons: ['😀'],hyperLink: 'https://github.com/ssshooter/mind-elixir-core',}

注意parent属性,它被用来在mindmap节点之间建立父/子关系。

使用Globals 来存储思维导图的源代码

 

ClassMethod StoreMindmapNode

///Store mindmap node
ClassMethodStoreMindmapNode()As%Status
{
    Try{
     
      Setdata={}.%FromJSON(%request.Content)
     
      Set^mindmap(data.id)=data.id /// set mindmap key
      Set^mindmap(data.id,"topic")=data.topic /// set topic subscript
      Set^mindmap(data.id,"style","fontSize")=data.style.fontSize /// set style properties subscripts
      Set^mindmap(data.id,"style","color")=data.style.color
      Set^mindmap(data.id,"style","background")=data.style.background
      Set^mindmap(data.id,"parent")=data.parent /// store parent id subscript
      Set^mindmap(data.id,"tags")=data.tags.%ToJSON() /// store tags subscript
      Set^mindmap(data.id,"icons")=data.icons.%ToJSON() /// store icons subscript
      Set^mindmap(data.id,"hyperLink")=data.hyperLink /// store hyperLink subscript
     
      Set%response.Status=200
      Set%response.Headers("Access-Control-Allow-Origin")="*"
      Write"Saved"
      Return$$$OK
    }Catcherr{
      write!,"Error name: ",?20,err.Name,
          !,"Error code: ",?20,err.Code,
          !,"Error location: ",?20,err.Location,
          !,"Additional data: ",?20,err.Data,!
      Return$$$NOTOK
  }
}

我们创建了一个名为^mindmap的Global。对于每个思维导图的属性,它被存储在一个Globals下标中。下标的键是mindmap的id属性。

删除思维导图节点的源代码 - kill the global

 

ClassMethod DeleteMindmapNode

///Delete mindmap node
ClassMethodDeleteMindmapNode(idAs%String)As%Status
{
    Try{
     
      Kill^mindmap(id) /// delete selected mindmap node using the id (global key)
     
      Set%response.Status=200
      Set%response.Headers("Access-Control-Allow-Origin")="*"
      Write"Deleted"
      Return$$$OK
    }Catcherr{
      write!,"Error name: ",?20,err.Name,
          !,"Error code: ",?20,err.Code,
          !,"Error location: ",?20,err.Location,
          !,"Additional data: ",?20,err.Data,!
      Return$$$NOTOK
  }
}

这个例子使用mindmap.id作为mindmap的Global Key,所以删除很容易: call Kill ^mindmap(<mindmap id>)

 获得所有存储内容的源代码- 用 $ORDER循环globals

 

ClassMethod GetMindmap - return all mindmap global nodes

///Get mindmap content
ClassMethodGetMindmap()As%Status
{
    Try{
     
      SetNodes=[]

 

      SetKey=$Order(^mindmap("")) /// get the first mindmap node stored - the root
      SetRow=0
     
      While(Key'=""){ /// while get child mindmap nodes
        DoNodes.%Push({}) /// create a item into result
        SetNodes.%Get(Row).style={}
        SetNodes.%Get(Row).id=Key /// return the id property
        SetNodes.%Get(Row).hyperLink=^mindmap(Key,"hyperLink") /// return the hyperlink property
        SetNodes.%Get(Row).icons=^mindmap(Key,"icons") /// return icons property
        SetNodes.%Get(Row).parent=^mindmap(Key,"parent") /// return parent id property
        SetNodes.%Get(Row).style.background=^mindmap(Key,"style","background") /// return the style properties
        SetNodes.%Get(Row).style.color=^mindmap(Key,"style","color")
        SetNodes.%Get(Row).style.fontSize=^mindmap(Key,"style","fontSize")
        SetNodes.%Get(Row).tags=^mindmap(Key,"tags") /// return tags property
        SetNodes.%Get(Row).topic=^mindmap(Key,"topic") /// return topic property (title mindmap node)
        SetRow=Row+1
       
        SetKey=$Order(^mindmap(Key)) /// get the key to the next mindmap global node
      }
     
      Set%response.Status=200
      Set%response.Headers("Access-Control-Allow-Origin")="*"
      WriteNodes.%ToJSON()
      Return$$$OK
    }Catcherr{
      write!,"Error name: ",?20,err.Name,
          !,"Error code: ",?20,err.Code,
          !,"Error location: ",?20,err.Location,
          !,"Additional data: ",?20,err.Data,!
      Return$$$NOTOK
  }
}

用$Order(^mindmap("")) - empty "" - 得到第一个mindmap Global (根节点)。对于每个属性值,我们使用^mindmap(Key,<property name>)。最后,调用$Order(^mindmap(Key))来获得下一个事件。

前端 

Mind-elixir和React被用来渲染和编辑mindmap,消耗使用IRIS构建的API后端。见mindmap的反应组件:

 

Mindmap React component - consuming IRIS REST API

importReactfrom"react";
importMindElixir, { E } from"mind-elixir";
importaxiosfrom'axios';

 

classMindmapextendsReact.Component {

 

    componentDidMount() {

 

        this.dynamicWidth = window.innerWidth;
        this.dynamicHeight = window.innerHeight;
       
            .then(res=> {
                if (res.data == "1") {
                    axios.get(`http://localhost:52773/global-mindmap/get`)
                        .then(res2=> {
                            this.ME = newMindElixir({
                                el:"#map",
                                direction:MindElixir.LEFT,
                                data:this.renderExistentMindmap(res2.data),
                                draggable:true, // default true
                                contextMenu:true, // default true
                                toolBar:true, // default true
                                nodeMenu:true, // default true
                                keypress:true// default true
                            });
                            this.ME.bus.addListener('operation', operation=> {
                                console.log(operation)
                   
                                if (operation.name == 'finishEdit' || operation.name == 'editStyle') {
                                    this.saveMindmapNode(operation.obj)
                                } elseif (operation.name == 'removeNode') {
                                    this.deleteMindmapNode(operation.obj.id)
                                }
                            })
                            this.ME.init();
                        })
                   
                } else {
                    this.ME = newMindElixir({
                        el:"#map",
                        direction:MindElixir.LEFT,
                        data:MindElixir.new("New Mindmap"),
                        draggable:true, // default true
                        contextMenu:true, // default true
                        toolBar:true, // default true
                        nodeMenu:true, // default true
                        keypress:true// default true
                    });
                    this.ME.bus.addListener('operation', operation=> {
                        console.log(operation)
           
                        if (operation.name == 'finishEdit' || operation.name == 'editStyle') {
                            this.saveMindmapNode(operation.obj)
                        } elseif (operation.name == 'removeNode') {
                            this.deleteMindmapNode(operation.obj.id)
                        }
                    })
                    this.saveMindmapNode(this.ME.nodeData)
                    this.ME.init();
                }

 

               
            })

 

    }

 

    render() {
        return (
            <divid="map"style={{ height:window.innerHeight + 'px', width:'100%' }}/>
        );
    }

 

    deleteMindmapNode(mindmapNodeId) {
        axios.delete(`http://localhost:52773/global-mindmap/delete/${mindmapNodeId}`)
            .then(res=> {
                console.log(res);
                console.log(res.data);
            })
    }

 

    saveMindmapNode(node) {

 

        axios.post(`http://localhost:52773/global-mindmap/save`, {
            topic: (node.topic == undefined ? "" : node.topic),
            id:node.id,
            style: (node.style == undefined ? "" : node.style),
            parent: (node.parent == undefined ? "" : node.parent.id),
            tags: (node.tags == undefined ? [] : node.tags),
            icons: (node.icons == undefined ? [] : node.icons),
            hyperLink: (node.hyperLink == undefined ? "" : node.hyperLink)
        })
            .then(res=> {
                console.log(res);
                console.log(res.data);
            })
    }

 

    renderExistentMindmap(data) {
       
        letroot = data[0]

 

        letnodeData = {
            id:root.id,
            topic:root.topic,
            root:true,
            style: {
                background:root.style.background,
                color:root.style.color,
                fontSize:root.style.fontSize,
            },
            hyperLink:root.hyperLink,
            children: []
        }

 

        this.createTree(nodeData, data)

 

        return { nodeData }
    }

 

    createTree(nodeData, data) {
        for(leti = 1; i < data.length; i++) {
            if(data[i].parent == nodeData.id) {
                letnewNode = {
                    id:data[i].id,
                    topic:data[i].topic,
                    root:false,
                    style: {
                        background:data[i].style.background,
                        color:data[i].style.color,
                        fontSize:data[i].style.fontSize,
                    },
                    hyperLink:data[i].hyperLink,
                    children: []
                }
                nodeData.children.push(newNode)
                this.createTree(newNode, data)
            }
        }
    }

 

   
}

 

exportdefaultMindmap;