创新项目实训
任务
已经实现了根据用户的分析行为,为用户推荐网页的功能,为了实现网页数据的可视化(当然仅仅是针对有文本的网页,多媒体类型的技术有限),决定采用思维导图的方式对网页中的文本进行可视化展示。
jsmind
jsMind 是一个显示/编辑思维导图的纯 javascript 类库,其基于 html5 canvas 和 svg 进行设计。jsMind 以 BSD 协议开源,在此基础上你可以在你的项目上任意使用。——引自官网
- 详细信息请参考官网
- 安装jsmind——
npm install jsmind
- 使用流程
- 在文件中引入样式等信息
//jsmind绘制流程图 import 'jsmind/style/jsmind.css' import jsMind from 'jsmind/js-legacy/jsmind.js'
- 创建容器,本项目使用的在el-dialog中展示。
<el-dialog title="提示" :visible.sync="dialogVisible" width="80%" > //jsmind容器 <div v-if="aiCompleted" id="jsmind_container" style="width:1200px;height: 400px;"></div> //后端信息生成之前,采用el-empty空状态 <div v-if="!aiCompleted"> <el-empty description="首次生成中,请耐心等待~"></el-empty> </div> <span slot="footer" class="dialog-footer"> <el-button type="primary" @click="closeDialog()">关 闭</el-button> </span> </el-dialog>
- 设置三个对象,分别是jsmind实例,mind数据以及jmoptions设置
data(){ return{ jm:null,//思维导图的实例 //mind示例 mind:{ /* 元数据,定义思维导图的名称、作者、版本等信息 */ "meta":{ "name":"example", "author": 'jsmind', }, /* 数据格式声明 */ "format":"node_array", /* 数据内容 */ "data":[ {"id":"root", "isroot":true, "topic":"jsMind"}, {"id":"easy", "parentid":"root", "topic":"Easy", "direction":"left"}, {"id":"easy1", "parentid":"easy", "topic":"Easy to show"}, {"id":"easy2", "parentid":"easy", "topic":"Easy to edit"}, {"id":"easy3", "parentid":"easy", "topic":"Easy to store"}, {"id":"easy4", "parentid":"easy", "topic":"Easy to embed"}, {"id":"open", "parentid":"root", "topic":"Open Source", "expanded":false, "direction":"right"}, {"id":"open1", "parentid":"open", "topic":"on GitHub"}, {"id":"open2", "parentid":"open", "topic":"BSD License"}, {"id":"powerful", "parentid":"root", "topic":"Powerful", "direction":"right"}, {"id":"powerful1", "parentid":"powerful", "topic":"Base on Javascript"}, {"id":"powerful2", "parentid":"powerful", "topic":"Base on HTML5"}, {"id":"powerful3", "parentid":"powerful", "topic":"Depends on you"}, ] }, //思维导图的设置 jmoptions:{ // options 将在下一章中详细介绍 container:'jsmind_container', // [必选] 容器的ID,或者为容器的对象 editable:true, // [可选] 是否启用编辑 theme:'greensea' // [可选] 主题 }, } }
- jsmind的初始化
initjsMind() { //创建新的实例 this.jm = new jsMind(this.jmoptions); //展示数据 this.jm.show(this.mind); },
- jsmind的销毁。如果不销毁的话,每次打开dialog都会导致又多出来一个思维导图,以此类推,无穷尽也… 没有找到官方的销毁方法,所以下面的方法可能会比较暴力。
closeDialog(){ //删除 if(this.jm){ delete this.jm; } //注意是jsmind容器的父容器 const container = document.getElementById('jsmind_container'); while (container.firstChild) { container.removeChild(container.firstChild); } //关闭图表 this.dialogVisible=false },
- 注意事项,有时候需要异步操作,即需要等待DOM挂载完毕后,才能进行jsmind的渲染
//方式1 await this.$nextTick() this.initjsMind() //方式2 setTimeout(()=>{ this.initjsMind() },500)
- 在文件中引入样式等信息
- 关于jsmind的其他内容
- 数据格式:jsMind 支持三种数据格式,分别是 node_tree、node_array 和 freemind 格式。jsMind 可以加载其中任一种格式,也能将数据导出为任一种格式。请参考官方文档
- node_tree
- freemind
- 主题:jsMind 默认提供了 15 种主题,你可以访问功能示例页面浏览这些主题。
- 样式:能够对节点背景颜色,节点文本,节点文字字体等多种元素设置样式。
- 数据格式:jsMind 支持三种数据格式,分别是 node_tree、node_array 和 freemind 格式。jsMind 可以加载其中任一种格式,也能将数据导出为任一种格式。请参考官方文档
- 贴个图
后端实现
- 分析jsmind的mind元素的基本结构,提取出一个基本的模版;结合通过爬虫提取到的网页信息。将二者让AI进行加工处理,得到我们需要的结构化数据的文本形式。
- 通过正则表达式对文本进行过滤,如去除不需要的注释等干扰信息。
- 通过使用
JSON.parse()
获得能够使用的JSON格式的数据。 - 传送给前端,进行渲染。
@PostMapping("/analyse/jsonData") public DataResponse analyseJsonData(@RequestBody DataRequest dataRequest)throws NoApiKeyException, InputRequiredException{ String rawJson=dataRequest.getString("rawJson"); // String rawJson="[ \n" + // " {\"A\": \"省份\", \"B\": \"GDP\"}, \n" + // " {\"A\": \"山东\", \"B\": 10}, \n" + // " {\"A\": \"河南\", \"B\": 20}, \n" + // " {\"A\": \"陕西\", \"B\": 50}, \n" + // " {\"A\": \"山西\", \"B\": 15}, \n" + // " {\"A\": \"福建\", \"B\": 100}, \n" + // " {\"A\": \"河北\", \"B\": 60}, \n" + // " {\"A\": \"宁夏\", \"B\": 200}, \n" + // " {\"A\": \"甘肃\", \"B\": 10} \n" + // "]"; String need=dataRequest.getString("need"); String message=""; message="原始JSON如下:\n"+rawJson+"\n"; message=message+"需求如下:\n"+need+"\n"; //AI生成结构化数据的文本形式 String result=genJsonData(message); //进行切分初步过滤 int startIndex = result.indexOf('[') ; // 获取"json"后一个字符的位置 int endIndex = result.lastIndexOf(']')+1; result=result.substring(startIndex,endIndex); System.out.println(result); return CommonMethod.getReturnData(200,result,"ok");
//分析网页 async handleUrl(data){ var tempUrl=null getRecommendByUrl({data:{url:data.url}}).then(response=>{ this.dialogVisible=true tempUrl=response.data }) setTimeout(()=>{ console.log(tempUrl) if(tempUrl.urldata==null){ analyseJsMind({data:{url:data.url}}).then(response=>{ if(response.code==200){ this.aiCompleted=true //对后端传来的数据进行过滤 var cleanedData=response.data cleanedData = cleanedData.replace(/\/\/.*$/gm, ''); cleanedData = cleanedData.replace(/^\s*\n*\"|\"\n*\s*$/g, ''); cleanedData = cleanedData.replace(/\s+/g, ' '); cleanedData = cleanedData.replace(/javascript/g,''); cleanedData = cleanedData.replace(/\`{3}/g, ''); cleanedData = cleanedData.replace(/;.*$/, ';') //文本JSON化 this.mind=JSON.parse(cleanedData) //初始化jsmind setTimeout(()=>{ this.initjsMind() },500) }else{ this.$message({ message: '警告哦,网页内容为空!', type: 'warning' }); } }) }else{ this.aiCompleted=true var cleanedData=tempUrl.urldata cleanedData = cleanedData.replace(/\/\/.*$/gm, ''); cleanedData = cleanedData.replace(/^\s*\n*\"|\"\n*\s*$/g, ''); cleanedData = cleanedData.replace(/\s+/g, ' '); cleanedData = cleanedData.replace(/javascript/g,''); cleanedData = cleanedData.replace(/\`{3}/g, ''); cleanedData = cleanedData.replace(/;.*$/, ';') this.mind=JSON.parse(cleanedData) setTimeout(()=>{ this.initjsMind() },500) } },1000) },