按钮实现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

猜你喜欢

转载自blog.csdn.net/zfan520/article/details/78623272