Skip to content

如何实现AI生成节点内容

目前AI能力非常流行,每个应用都给自己加上了AI的能力提高竞争力,那么在使用了simple-mind-map的情况下如何添加AI的能力呢,本教程会详细的教你如何实现。

首先要说明的是本教程并不会真的实现一个可用的AI能力,只是在假设你要实现该功能的前提下来教你如何调用对应的API来实现你想要的效果。

其次AI返回的数据结构不尽相同,你都需要自行转换成simple-mind-map的结构类型。

自动生成整个思维导图

一次生成

通过AI生成整个思维导图并且一次直接生成,这个其实就是普通的回显功能,那么你可以在实例化时通过data传入生成的数据:

js
const mindMap = new MindMap({
    el,
    data: {
        data: {
            text: '我是自动生成的节点'
        },
        children: [
            {
                data: {
                    text: '子节点'
                },
                children: []
            }
        ]
    }
})

也可以在实例化之后使用setData方法设置:

js
mindMap.setData({
    data: {
        text: '我是自动生成的节点'
    },
    children: [
        {
            data: {
                text: '子节点'
            },
            children: []
        }
    ]
})

依次生成节点

如果你想像ChatGPT一样依次生成节点,那么推荐使用updateData方法增量更新节点数据,而不是手动获取到之前插入的节点实例,再调用命令来插入下级节点,这样会复杂很多,当然,如果你能轻松的知道当前创建到哪里了,并且下一个节点在哪个节点下创建,可以忽略。

updateData方法是v0.9.9+的方法,之前的版本可以使用下面的方法:

js
const updateData = (data) => {
    mindMap.renderer.setData(data)
    mindMap.render()
    mindMap.command.addHistory()
}

增量更新的前提是之前生成的节点都存在uid,并且不会变化,这样调用updateData方法渲染时会根据uid来复用之前的节点,只创建新的节点,达到依次生成的目的。

比如第一次返回的数据:

js
const data = {
    data: {
        text: '根节点',
        uid: '1'
    },
    children: []
}

mindMap.setData(data)

第二次返回的数据:

js
const data = {
    data: {
        text: '根节点',
        uid: '1'
    },
    children: [
        {
            data: {
                text: '二级节点',
                uid: '2'
            },
            children: []
        }
    ]
}

mindMap.updateData(data)

以此类推,这样虽然是整个数据更新,但是因为复用的原因画布呈现的是依次生成新节点的效果。

当生成的节点多了会有个问题,就是新生成的节点在画布外看不见了,所以我们要将新生成的节点移动到画布中心,首先可以监听data_change_detail事件来获取到详细的更新数据,找出其中新创建的节点数据,然后使用findNodeByUid方法找出对应的节点实例,最后调用moveNodeToCenter方法将该节点移动到画布中心即可。

js
mindMap.on('data_change_detail', (list) => {
    // 找出新创建节点中的最后一个
    const lastCreate = list.filter((item) => {
        return item.action === 'create'
    })[0]
    if (lastCreate) {
        const uid = lastCreate.data.data.uid
        const node = mindMap.renderer.findNodeByUid(uid)
        if (node) {
            mindMap.renderer.moveNodeToCenter(node)
        }
    }
})

当节点数据多了,可能data_change_detail事件触发时节点树还没渲染完毕,导致获取不到节点,解决这个问题可以通过监听node_tree_render_end事件:

js
let waitUid = ''
mindMap.on('data_change_detail', (list) => {
    // ...
    if (lastCreate) {
        // ...
        if (node) {
            mindMap.renderer.moveNodeToCenter(node)
        } else {
            waitUid = uid
        }
    }
})

mindMap.on('node_tree_render_end', () =>{
    if (waitUid) {
        waitUid = ''
        const node = mindMap.renderer.findNodeByUid(waitUid)
        if (node) {
            mindMap.renderer.moveNodeToCenter(node)
        }
    }
})

当在data_change_detail事件中没有获取到节点实例就将该uid保存起来,然后在node_tree_render_end事件里判断是否有保存的uid,是的话就获取该节点实例并移动到画布中心。

最后,当自动生成节点中最好禁止用户操作,否则可能会产生异常。

完整示例

在某个节点下自动生成新节点

在某个节点下自动生成新节点,如果也要依次生成,那么可以使用前面的增量更新数据的方式。如果一次生成,那么可以简单的调用插入新节点的命令即可。

一次生成下级节点

js
// 插入一个子节点
mindMap.execCommand('INSERT_CHILD_NODE', 
    false,
    node,
    {
        data: {
            text: '三级节点'
        },
        children: []
    },
    [
        {
            data: {
                text: '三级节点的子节点'
            },
            children: []
        }
    ]
)

// 插入多个子节点
mindMap.execCommand('INSERT_MULTI_CHILD_NODE', node, [
    {
        data: {
            text: '三级节点'
        },
        children: []
    },
    {
        data: {
            text: '三级节点'
        },
        children: []
    }
])

一次生成兄弟节点

js
// 插入一个兄弟节点
mindMap.execCommand('INSERT_NODE', 
    false,
    node,
    {
        data: {
            text: '二级节点'
        },
        children: []
    },
    [
        {
            data: {
                text: '二级节点的子节点'
            },
            children: []
        }
    ]
)

// 插入多个兄弟节点
mindMap.execCommand('INSERT_MULTI_NODE', node, [
    {
        data: {
            text: '二级节点'
        },
        children: []
    },
    {
        data: {
            text: '二级节点'
        },
        children: []
    }
])

这样新创建的节点默认会被激活但不进入编辑,如果你连激活都不想要的话,那么可以通过将实例化选项createNewNodeBehavior设置为notActive

当自动生成结束后你又想恢复创建新节点时自动进入编辑状态,那么可以通过updateConfig方法修改createNewNodeBehavior

js
mindMap.updateConfig({
    createNewNodeBehavior: 'default'
})

完整示例

MIT License.