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 来存储思维导图的源代码
/// Store mindmap node
ClassMethod StoreMindmapNode() As %Status
{
Try {
Set data = {}.%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
} Catch err {
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
/// Delete mindmap node
ClassMethod DeleteMindmapNode(id As %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
} Catch err {
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
/// Get mindmap content
ClassMethod GetMindmap() As %Status
{
Try {
Set Nodes = []
Set Key = $Order(^mindmap("")) /// get the first mindmap node stored - the root
Set Row = 0
While (Key '= "") { /// while get child mindmap nodes
Do Nodes.%Push({}) /// create a item into result
Set Nodes.%Get(Row).style = {}
Set Nodes.%Get(Row).id = Key /// return the id property
Set Nodes.%Get(Row).hyperLink = ^mindmap(Key,"hyperLink") /// return the hyperlink property
Set Nodes.%Get(Row).icons = ^mindmap(Key,"icons") /// return icons property
Set Nodes.%Get(Row).parent = ^mindmap(Key,"parent") /// return parent id property
Set Nodes.%Get(Row).style.background = ^mindmap(Key,"style", "background") /// return the style properties
Set Nodes.%Get(Row).style.color = ^mindmap(Key,"style", "color")
Set Nodes.%Get(Row).style.fontSize = ^mindmap(Key,"style", "fontSize")
Set Nodes.%Get(Row).tags = ^mindmap(Key,"tags") /// return tags property
Set Nodes.%Get(Row).topic = ^mindmap(Key,"topic") /// return topic property (title mindmap node)
Set Row = Row + 1
Set Key = $Order(^mindmap(Key)) /// get the key to the next mindmap global node
}
Set %response.Status = 200
Set %response.Headers("Access-Control-Allow-Origin")="*"
Write Nodes.%ToJSON()
Return $$$OK
} Catch err {
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的反应组件:
import React from "react";
import MindElixir, { E } from "mind-elixir";
import axios from 'axios';
class Mindmap extends React.Component {
componentDidMount() {
this.dynamicWidth = window.innerWidth;
this.dynamicHeight = window.innerHeight;
.then(res => {
if (res.data == "1") {
.then(res2 => {
this.ME = new MindElixir({
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)
} else if (operation.name == 'removeNode') {
this.deleteMindmapNode(operation.obj.id)
}
})
this.ME.init();
})
} else {
this.ME = new MindElixir({
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)
} else if (operation.name == 'removeNode') {
this.deleteMindmapNode(operation.obj.id)
}
})
this.saveMindmapNode(this.ME.nodeData)
this.ME.init();
}
})
}
render() {
return (
<div id="map" style={{ height: window.innerHeight + 'px', width: '100%' }} />
);
}
deleteMindmapNode(mindmapNodeId) {
.then(res => {
console.log(res);
console.log(res.data);
})
}
saveMindmapNode(node) {
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) {
let root = data[0]
let nodeData = {
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(let i = 1; i < data.length; i++) {
if(data[i].parent == nodeData.id) {
let newNode = {
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)
}
}
}
}
export default Mindmap;