按钮实现echarts添加与删除节点

点击打开链接

1、echarts文件将节点信息通过reducer传出

import React from  'react'
import echarts from  'echarts/lib/echarts'  //必须
import  'echarts/lib/component/tooltip'
import  'echarts/lib/component/legend'
import  'echarts/lib/chart/pie'
import  'echarts/lib/chart/graph'
import { connect } from  'react-redux' ;
import $ from  'jquery' ;
 
class PieReact extends React.Component {
   constructor(props) {
     super (props)
     this .initPie =  this .initPie.bind( this )
     this .state = {
       echartsdata:  null ,
       echartslinks:  null
     }
   }
   initPie() {
     //节点数据
     const TestNodeOption = {
       animationDurationUpdate: 1500,
       animationEasingUpdate:  'quinticInOut' ,
       series: [
         {
           type:  'graph' ,
           zoom: 2,
           layout:  'force' ,
           hoverAnimation:  true ,
           // 节点大小
           name:  'aiii' ,
           symbolSize: 30,
           focusNodeAdjacency:  true ,
           roam:  true ,
           categories: [{
             name:  '一级节点' ,
             itemStyle: {
               normal: {
                 color:  "#009800" //颜色
               }
             }
           }, {
             name:  '二级节点' ,
             itemStyle: {
               normal: {
                 color:  "#9ccc65" ,
               }
             }
           }, {
             name:  '三级节点' ,
             itemStyle: {
               normal: {
                 color:  "#f2b368" ,
               }
             }
           }, {
             name:  '四级节点' ,
             itemStyle: {
               normal: {
                 color:  "#53bc65" ,
               }
             }
           }, {
             name:  '五级节点' ,
             itemStyle: {
               normal: {
                 color:  "#778866" ,
               }
             }
           }],
           // 节点标签
           label: {
             normal: {
               show:  true ,
               textStyle: {
                 fontSize:  '12rem'
               },
             }
           },
           //放大程度
           force: {
             repulsion: 200
           },
           edgeSymbolSize: [4, 50],
           // 数据
             //可获取网络数据data:this.state.echartsdata
             //采用写死的数据
           data: [
             { category: 0, name:  "六年级数学知识大纲" , dataid: 1 }
             ,
             { category: 1, name:  "数与代数" , dataid: 2 }
             ,
             { category: 1, name:  "图形与几何" , dataid: 3 }
             ,
             { category: 1, name:  "统计与概率" , dataid: 4 }
             ,
             { category: 1, name:  "综合与实践" , dataid: 5 }
             ,
             { category: 2, name:  "分数乘法" , dataid: 6 }
             ,
             { category: 2, name:  "分数除法" , dataid: 7 }
             ,
             { category: 2, name:  "比" , dataid: 8 }
             ,
             { category: 2, name:  "百分数" , dataid: 9 }
             ,
             { category: 2, name:  "位置与方向" , dataid: 10 }
             ,
             { category: 2, name:  "圆" , dataid: 11 }
             ,
             { category: 2, name:  "统计" , dataid: 12 }
             ,
             { category: 2, name:  "确定起跑线" , dataid: 13 }
             ,
             { category: 2, name:  "数学广角" , dataid: 14 }
             ,
             { category: 2, name:  "string" , dataid: 894 }
           ],
           // 建立关系
             //可获取网络关系links:this.state.echartslinks
             //采用写死的关系
           links:
             [{ source:  "六年级数学知识大纲" , target:  "数与代数"  }
             ,
             { source:  "六年级数学知识大纲" , target:  "图形与几何"  }
             ,
             { source:  "六年级数学知识大纲" , target:  "统计与概率"  }
             ,
             { source:  "六年级数学知识大纲" , target:  "综合与实践"  }
             ,
             { source:  "数与代数" , target:  "分数乘法"  }
             ,
             { source:  "数与代数" , target:  "分数除法"  }
             ,
             { source:  "数与代数" , target:  "比"  }
             ,
             { source:  "数与代数" , target:  "百分数"  }
             ,
             { source:  "图形与几何" , target:  "位置与方向"  }
             ,
             { source:  "图形与几何" , target:  "圆"  }
             ,
             { source:  "统计与概率" , target:  "统计"  }
             ,
             { source:  "综合与实践" , target:  "确定起跑线"  }
             ,
             { source:  "综合与实践" , target:  "数学广角"  }
             ,
             { source:  "数与代数" , target:  "string"  }],
           // links:this.state.echartslinks,
           // 连接线样式
           lineStyle: {
             normal: {
               opacity: 0.9, //连接线的透明度
               width: 1,  //连接线的粗细
               curveness: 0, //连线的弧度
             }
           }
         }
       ],
     };
     var  myChart = echarts.init( this .ID)  //初始化echarts
//用于实时接收父组件传过来的值
     var  ifDelete =  this .props.eventsOption.ifDelete
     var  ifAdd =  this .props.eventsOption.ifAdd
     var  selectName =  this .props.eventsOption.selectName
     var  selectIndex =  this .props.eventsOption.selectIndex
     var  selectcategory =  this .props.eventsOption.selectcategory
     var  newname =  this .props.eventsOption.newname;
     var  newcategory =  this .props.eventsOption.newcategory;
 
     //设置options,options即为数据,此步骤是自定义画布myChart加载数据
     if  (myChart.getOption() == undefined) {
       myChart.setOption(TestNodeOption)
     }
     else  myChart.setOption(myChart.getOption())
     window.onresize =  function  () {
       myChart.resize()
     }
     //根据父节点传过来的消息,在此处判断是删除节点还是添加节点
     if  (ifDelete) {
       deleteNode();
     else  if  (ifAdd) {
       addNode();
     }
     //删除节点函数
     function  deleteNode() {
       let options = myChart.getOption(); //获取已生成图形的Option
       let nodesOption = options.series[0].data; //获得所有节点的数组
       let linksOption = options.series[0].links; //获得所有连接的数组
       var  categoryLength = options.series[0].categories.length;
       let nodeLength = nodesOption.length
       //如果要添加节点,有两个步骤,首先data出现该节点的内容,然后links含有它的链接。   
       let newsource =  ''
       //将选择的节点的子节点的父节点设为该节点的父节点
       if  (selectIndex == 0) { alert( "您确定要删除根节点吗?" ); }
       else  {
         for  (let m  in  linksOption) {
           if  (linksOption[m].target == selectName) {
             newsource = linksOption[m].source //找到当前节点的父节点
             linksOption.splice(m, 1) //还应该删除连线才对
           }
         }
         for  (let m  in  linksOption) {
           if  (linksOption[m].source == selectName) {
             linksOption[m].source = newsource
             // linksNodes.push(linksOption[m].target);
           }
         } //然后删除
         nodesOption.splice(selectIndex, 1); //这个属性从0开始计数是同数组的索引相同
         myChart.setOption(options);
         console.log(options)
       }
     }
     myChart.off( 'contextmenu' , showMenu)
     function  showMenu(param) {
     }
     //单击,通过reducer将节点信息传出去,让其他组件接收到节点信息
     myChart.on( 'click' , transIndex.bind( this ))
     function  transIndex(param) {
       const { setEchartState } =  this .props
       setEchartState({
         type:  'EchartsIndexName' ,
         payload: {
           index: param.dataIndex,
           name: param.data.name,
           knowid: param.data.knowid,
           category: param.data.category
         }
       })
     }
     //添加节点函数
     function  addNode() {
       let options = myChart.getOption(); //获取已生成图形的Option param
       let nodesOption = options.series[0].data; //获得所有节点的数组
       let linksOption = options.series[0].links; //获得所有连接的数组
       let newNode = {
         name: newname, /*nodesOption.length + selectName,  data.name */
         draggable:  true ,
         category: newcategory /*selectcategory + 1  data.category */
       }
       let newLink = {
         source: selectName,
         target: newNode.name
       }
       linksOption.push(newLink);
       nodesOption.push(newNode);
       myChart.setOption(options);
     }
 
   }
         getData() {
           $.ajax({
             url:  "/knowledge_map/showKnowledgeMapData" ,
             type:  "GET" ,
             dataType:  "json" ,
             data: {  "kmapid" : 1 },
             success:  function  (data) {
               this .setState({
                 echartsdata:data.data,
                 echartslinks:data.links
               });
               console.log( this .state.echartsdata);
               console.log( this .state.echartslinks);
             }.bind( this ),
             error:  function  (xhr, status, err) {
             }.bind( this )
           });
         }
   componentDidMount() {
     // 若数据为网络数据,可在此处进行网络请求获取网络数据
     //this.getData();
     this .initPie()
   }
 
   componentDidUpdate() {
     this .initPie()
   }
   render() {
     const { width =  "100%" , height =  '700px'  } =  this .props
     return  <div ref={ID =>  this .ID = ID} style={{ width, height }}></div>
   }
}
function  mapStateToProps(state) {
   return  {
   };
}
 
 
function  mapDispatchToProps(dispatch) {
   return  {
     setEchartState: (state) => dispatch(state)
   };
}
 
export  default  connect(
   mapStateToProps,
   mapDispatchToProps
)(PieReact);


2、父组件通过reducer收到节点信息,控制删除与添加

import React, { Component } from  'react' ;
import { Link} from  'react-router-dom' ;
import { connect } from  'react-redux' ;
import  'antd/dist/antd.css' ;
import $ from  'jquery' ;
import { Layout, Menu, Breadcrumb, Icon, Row, Col, Input, Card, Select, Button, Form, Tabs, Modal } from  'antd' ;
import PieReact from  '../echarts/TestEcharts.js' ;
import Addknowledge from  './common_knowledgeManage/Addknowledge.js'
const { SubMenu } = Menu;
const FormItem = Form.Item;
const Option = Select.Option;
const TabPane = Tabs.TabPane;
const confirm = Modal.confirm;
// 删除确定弹出框
class KnowledgeManage_Echarts_Slider extends Component {
   constructor() {
     super ()
//定义此页面状态机
     this .state = {
//echartsoption用于将数据传给子控件
       echartsoption: {
         ifDelete:  false ,
         selectName:  '' ,
         selectIndex: -1,
         ifAdd:  false ,
         selectcategory: -1,
         newcategory:-1,
         newname: ''
       },
       visible:  false ,
       newcategory:-1,
       newname: '' ,
     }
   }
 
   showModal() {
     this .setState({
       visible:  true ,
     });
   }
   handleOk() {
     const { EchartsIndexName } =  this .props;
     this .setState({
       echartsoption: {
         ifDelete:  true ,
         ifAdd:  false ,
         selectIndex: EchartsIndexName.index,
         selectName: EchartsIndexName.name,
         selectcategory: EchartsIndexName.selectcategory,
       },
       visible:  false ,
     });
   handleCancel() {
     this .setState({
       visible:  false ,
     });
   }
//此函数用以另一添加节点的控件操纵,将添加节点的信息通过此函数获取,并将节点信息传给echarts控件
   handleAdd(sindex,sname,scategory,name,category){
     this .setState({
       echartsoption: {
         ifAdd:  true ,
         ifDelete:  false ,
         selectIndex: sindex,
         selectName: sname,
         selectcategory: scategory,
         newcategory:category,
         newname:name
       },
     })
   }
   render() {
     const { EchartsIndexName } =  this .props;
     console.log( 'deleteIndexName render' )
     console.log(EchartsIndexName)
     return  (
       <Layout>
         <div style={{ background:  '#fff' , paddingTop:  '20px'  }}>
           <Row>
             <Col span={14}>
             </Col>
             <Col span={2}>
               <Button type= "primary"  size= "large"  /* onClick={this.addNode.bind(this)} */ >添加节点</Button>
             </Col>
             <Col span={2}>
               <Button type= "primary"  size= "large"  onClick={ this .showModal.bind( this )}>删除节点</Button>
             </Col>
           </Row>
         </div>
         <Layout style={{ padding:  '10px 0' , background:  '#fff'  }}>
           <Sider width={700} style={{ background:  '#fff' , paddingLeft:  '15px' , paddingTop:  '30px'  }}>
             <Card>
                 //此处引用该控件,将this.state.echartsoption的值通过eventsOption传给echarts控件
               <PieReact eventsOption={ this .state.echartsoption}></PieReact>
             </Card>
           </Sider>
           <Content style={{ padding:  '0 24px' , minHeight: 280 }}>
                 //此处引用添加节点的控件,将handleAdd函数传给该控件,以方便调用
           <Addknowledge handleAdd={ this .handleAdd.bind( this )}></Addknowledge>
           </Content>
         </Layout>
         <Modal
           visible={ this .state.visible}
           onOk={ this .handleOk.bind( this )}
           onCancel={ this .handleCancel.bind( this )}
         >
           <span><Icon type= "close"  style={{ color:  "#F00" , fontSize: 15 }} />确定要删除该节点吗?
           </span>
         </Modal>
       </Layout>
     );
   }
}
//通过reducer接收echart控件传过来的节点信息
function  mapStateToProps(state) {
   return  {
     EchartsIndexName: state.reducer_echarts.EchartsIndexName
   };
}
function  mapDispatchToProps(dispatch) {
   return  {
   };
}
export  default  connect(
   mapStateToProps,
   mapDispatchToProps
)(KnowledgeManage_Echarts_Slider);


3、兄弟组件添加节点信息

import React, { Component } from  'react' ;
import $ from  'jquery' ;
import { Link, HashRouter } from  'react-router-dom' ;
import { connect } from  'react-redux' ;
import  'antd/dist/antd.css' ;   // Add
import { Tabs, Icon, Form, Input, Button, Select, Layout, Breadcrumb, Card, Modal, Upload, Row, Col } from  'antd' ;
const { Header, Content, Footer, Sider } = Layout;
const confirm = Modal.confirm;
const TabPane = Tabs.TabPane;
const FormItem = Form.Item;
const Option = Select.Option;
const tailFormItemLayout = {
   wrapperCol: {
     xs: {
       span: 24,
       offset: 0,
     },
     sm: {
       span: 14,
       offset: 6,
     },
   },
};
 
class Addknowledge extends React.Component {
   constructor(props) {
     super (props);
     this .state = {
       echartsoption: {
         ifDelete:  false ,
         selectName:  '' ,
         selectIndex: -1,
         ifAdd:  false ,
         selectcategory: -1,
         newcategory:-1,
         newname: ''
       }
   }
}
   changename(e) {
     this .setState({
       newname: e.target.value
     });
   }
   changecategory(e) {
     this .setState({
       newcategory: +e.target.value
     });
   }
     
   handleClick() {
     //获取reducer中的值
     const { EchartsIndexName } =  this .props;
     //从父组件获取handleAdd函数
     console.log( this .props.handleAdd);
     //将本页面的参数通过函数传给父页面
     this .props.handleAdd(EchartsIndexName.index,EchartsIndexName.name,EchartsIndexName.category, this .state.newname, this .state.category);
   }
 
   render() {
     return  (
       <div style={{ paddingTop:  '30px'  }}>
         <Card style={{ height:  '500px'  }}>
           <div style={{ paddingTop:  '10px'  }}>
             <Form>
               <FormItem
                 label= "知识点名称"
                 labelCol={{ span: 4 }}
                 wrapperCol={{ span: 8 }}
                 hasFeedback
               >
                 <Input onChange={ this .changename.bind( this )} />
               </FormItem>
               <FormItem
                 label= "知识点类别"
                 labelCol={{ span: 4 }}
                 wrapperCol={{ span: 8 }}
                 hasFeedback
               >
               <span><Input onChange={ this .changecategory.bind( this )} />请输入0-9以内的数字</span>
               </FormItem>
               <FormItem>
                     //单击确定,触发handleClick事件
                 <Button type= "primary"  style={{ marginLeft:  "100px"  }} onClick={ this .handleClick.bind( this )}>确定</Button>
               </FormItem>
             </Form>
           </div>
         </Card>
       </div>
     );
   }
}
Addknowledge = Form.create()(Addknowledge);
//通过reducer获取节点信息
function  mapStateToProps(state) {
   return  {
     EchartsIndexName: state.reducer_echarts.EchartsIndexName
   };
}
function  mapDispatchToProps(dispatch) {
   return  {
   };
}
export  default  connect(
   mapStateToProps,
   mapDispatchToProps
)(Addknowledge);

4、总结

通过按钮实现echarts节点的删除和添加,需要将echarts中节点的索引和name传出到其他页面,采用的是reducer的机制,其他页面将删除和添加节点的操作信息、新增节点的信息以及选中节点本身的信息通过子父组件或者兄弟组件传值的方式再次传入echarts页面,此时便达到了节点实时刷新的效果。

若echarts页面和其他控制页面不是子父组件或者兄弟组件的形式存在,可采用全局监听的机制,此时可用PubSubjs的方式实现组件之间传值,也可达到实时刷新的机制。
PubSubjs机制可参考http://blog.csdn.net/zfan520/article/details/78612088

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值