使用Vue-neo4j實(shí)現(xiàn)繪制三國(guó)人物圖譜關(guān)系
前言
發(fā)現(xiàn)一個(gè)很有用的Vue插件:https://www.npmjs.com/package/vue-neo4j
這個(gè)能在前端直連neo4j服務(wù)器啦,下圖就是測(cè)試效果繪制三國(guó)人物圖譜關(guān)系
版本說明
- vue
3.0版本
- vue-neo4j
0.4.8版本
- neo4j服務(wù)端版本
4.3.6版本
,可以直接去官網(wǎng)下載。 - echarts
5.22版本
開發(fā)說明
一、windows服務(wù)器部署neo4j
1、部署jdk11, 因?yàn)閚eo4j 4.3.6使用的版本是jdk11以上,否則啟動(dòng)不了哦
2、下載neo4j,解壓
3、到 .\conf目錄修改 neo4j.conf文件修改default_listen_address為0.0.0.0,因?yàn)椴桓牡脑?,?huì)導(dǎo)致啟動(dòng)后只能本機(jī)訪問
4、cmd到.\bin目錄執(zhí)行 noe4j console. 這樣就完成啟動(dòng)了
5、瀏覽器打開網(wǎng)址 http://127.0.0.1:7474
默認(rèn)密碼為neo4j/neo4j 首次進(jìn)入會(huì)提示修改密碼
二、vue3.0 版本前端工程說明
1、引入依賴 yarn add vue-neo4j
2、由于vue-neo4j 0.4.8 該版本只適配vue2.0版本,所以要改下源碼,把 Vue.property.$neo4j
改為 Vue.config.globalProperties.$neo4j
3、main.js引入
import VueNeo4j from 'vue-neo4j'; let app = createApp(App); app.use(VueNeo4j );
4、邏輯編寫
<template> <div class="neo4jMain"> <div class="addContent"> <el-form :inline="true" :model="formInline" :rules="rules" ref="neo4jform"> <el-form-item label="開始節(jié)點(diǎn)名稱" prop="startNode"> <el-input v-model="formInline.startNode" placeholder="請(qǐng)輸入開始節(jié)點(diǎn)名稱"></el-input> </el-form-item> <el-form-item label="關(guān)系名稱" prop="relationName"> <el-input v-model="formInline.relationName" placeholder="請(qǐng)輸入關(guān)系名稱"></el-input> </el-form-item> <el-form-item label="結(jié)束節(jié)點(diǎn)名稱" prop="endNode"> <el-input v-model="formInline.endNode" placeholder="請(qǐng)輸入結(jié)束節(jié)點(diǎn)名稱"></el-input> </el-form-item> <el-form-item> <el-button type="primary" @click="onSubmit">提交</el-button> <!-- <el-button type="primary" @click="onDelete">清空表</el-button>--> </el-form-item> </el-form> </div> <div class="echarts" ref="echarts"> </div> </div> </template> <script> import * as echarts from 'echarts' export default { name: "Main.vue", mounted() { this.query(); }, data() { return { formInline: { startNode: '', endNode: '', relationName: '' }, rules: { startNode: [{required: true, trigger: 'blur'}], endNode: [{required: true, trigger: 'blur'}], relationName: [{required: true, trigger: 'blur'}] }, protocol: 'bolt', host: '127.0.0.1', port: 7687, username: 'neo4j', password: '123456', echartsData: [], nodesRelation: [] } }, methods: { onDelete() { this.connect(); const session = this.$neo4j.getSession(); let cypher = `match p=(n:Person)-[]->(m:Person) delete p `; session.run(cypher); cypher = `MATCH (n:Person) delete n`; session.run(cypher).then(() => { session.close() }); this.query(); }, initEcharts() { // 基于準(zhǔn)備好的dom,初始化echarts實(shí)例 let myChart = echarts.init(this.$refs.echarts) // 繪制圖表 myChart.setOption({ title: { text: 'Neo4j 圖譜關(guān)系' }, tooltip: {}, animationDurationUpdate: 1500, animationEasingUpdate: 'quinticInOut', series: [ { type: 'graph', layout: 'force', force: { edgeLength: 40, repulsion: 50, gravity: 0.1 }, symbolSize: 50, roam: true, label: { show: true }, edgeSymbol: ['circle', 'arrow'], edgeSymbolSize: [4, 10], edgeLabel: { fontSize: 20 }, data: this.echartsData, // links: [], links: this.nodesRelation, lineStyle: { opacity: 0.9, width: 2, curveness: 0 } } ] }); }, query() { this.connect(); const session = this.$neo4j.getSession(); let cypher = `match p=(n:Person)-[]->(m:Person) return p limit 1000`; session.run(cypher).then(res => { let records = res.records; let nodes = new Set(); this.nodesRelation = []; for (let i = 0; i < records.length; i++) { nodes.add(records[i]._fields[0].segments[0].start.properties.name); nodes.add(records[i]._fields[0].segments[0].end.properties.name); this.nodesRelation.push({ source: records[i]._fields[0].segments[0].start.properties.name, target: records[i]._fields[0].segments[0].end.properties.name, lineStyle: { curveness: 0 }, label: { show: true, formatter: function() { return records[i]._fields[0].segments[0].relationship.type } } }); } let curveness = [0, 0.4, -0.4, 0.3, -0.3, 0.2, -0.2, 0.1, -0.1]; for (let j = 0; j < this.nodesRelation.length; j++) { let repeatNumber = 0; for (let s = j+1; s < this.nodesRelation.length; s++) { let r1 = this.nodesRelation[j]; let r2 = this.nodesRelation[s]; if (r1.source === r2.source && r1.target === r2.target) { repeatNumber = repeatNumber + 1; } else if (r1.target === r2.source && r1.source === r2.target) { repeatNumber = repeatNumber + 1; } } this.nodesRelation[j].repeatNumber = repeatNumber; } for (let j = 0; j < this.nodesRelation.length; j++) { console.log(this.nodesRelation[j].repeatNumber); this.nodesRelation[j].lineStyle.curveness = curveness[this.nodesRelation[j].repeatNumber]; } this.echartsData = []; nodes.forEach((e) => { let index = Math.ceil(Math.random()*10); let color = () => { if (index%4===0) { return '#228B22' } else if (index%4===1) { return '#FFFF00' } else if (index%4===2) { return '#20B2AA' } else if (index%4===3) { return '#FFB6C1' } return '#87CEFA'; } this.echartsData.push({ name: e, x: Math.random() * 100, y: Math.random() * 100, itemStyle: { color: color() } }); }) this.initEcharts(); }).then(() => { session.close() }); }, onSubmit() { this.$refs.neo4jform.validate((valid) => { if (valid) { this.connect(); const session = this.$neo4j.getSession(); let cypher = `Merge (n:Person{name: '${this.formInline.startNode}'}) Merge (m:Person{name: '${this.formInline.endNode}'}) Merge (n)-[r:${this.formInline.relationName}]->(m)`; session.run(cypher).then(() => { this.formInline = { startNode: '', endNode: '', relationName: '' }; this.query(); }).then(() => { session.close() }); } }) }, connect() { return this.$neo4j.connect(this.protocol, this.host, this.port, this.username, this.password); }, driver() { // Get a driver instance return this.$neo4j.getDriver() }, testQuery() { // Get a session from the driver const session = this.$neo4j.getSession() // Or you can just call this.$neo4j.run(cypher, params) session.run('MATCH (n) RETURN n') .then(res => { console.log(res) // console.log(res.records[0].get('count')) }) .then(() => { session.close() }) } } } </script> <style scoped lang="less"> .neo4jMain { height: 100%; display: flex; flex-direction: column; .addContent { padding: 15px; box-shadow: -10px 0 10px #D3D3D3, /*左邊陰影*/ 10px 0 10px #D3D3D3, /*右邊陰影*/ 0 -10px 10px #D3D3D3, /*頂部陰影*/ 0 10px 10px #D3D3D3; } .echarts { background-color: #333; flex: 1; flex-grow: 1; } } </style>
心得:
- 優(yōu)點(diǎn)是前端可以直接操作數(shù)據(jù)庫(kù),弊端是數(shù)據(jù)庫(kù)配置暴露了。
- 建議還是通過后端連接數(shù)據(jù)庫(kù)操作數(shù)據(jù)。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
談?wù)勔騐ue.js引發(fā)關(guān)于getter和setter的思考
最近因?yàn)楣镜男马?xiàng)目決定使用Vue.js來做,但在使用的過程中發(fā)現(xiàn)了一個(gè)有趣的事情,因?yàn)榘l(fā)現(xiàn)的這個(gè)事情展開了一些對(duì)于getter和setter的思考,具體是什么下面通過這篇文章來一起看看吧,有需要的朋友們可以參考學(xué)習(xí)。2016-12-12解決echarts 一條柱狀圖顯示兩個(gè)值,類似進(jìn)度條的問題
這篇文章主要介紹了解決echarts 一條柱狀圖顯示兩個(gè)值,類似進(jìn)度條的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-07-07Vue中使用video.js實(shí)現(xiàn)截圖和視頻錄制與下載
這篇文章主要為大家詳細(xì)介紹了Vue中如何使用video.js實(shí)現(xiàn)截圖和視頻錄制與下載,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-03-03基于Vue3和Element Plus實(shí)現(xiàn)可擴(kuò)展的表格組件
在開發(fā)過程中,我們經(jīng)常需要?jiǎng)?chuàng)建具有復(fù)雜功能的表格組件,本文將介紹如何使用 Vue 3 和 Element Plus 庫(kù)來構(gòu)建一個(gè)可擴(kuò)展的表格組件,文中有詳細(xì)的代碼示例供大家參考,需要的朋友可以參考下2024-07-07vue3如何通過provide和inject實(shí)現(xiàn)多層級(jí)組件通信
這篇文章主要介紹了vue3如何通過provide和inject實(shí)現(xiàn)多層級(jí)組件通信,本文通過實(shí)例代碼給大家講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-11-11vue實(shí)現(xiàn)一個(gè)懶加載的樹狀表格實(shí)例
這篇文章主要介紹了vue實(shí)現(xiàn)一個(gè)懶加載的樹狀表格實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05Vue使用json-server進(jìn)行后端數(shù)據(jù)模擬功能
這篇文章主要介紹了Vue使用json-server進(jìn)行后端數(shù)據(jù)模擬功能,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2018-04-04