JTopo踩坑记 -- React项目中使用JTopo

JTopo踩坑记 – React项目中使用JTopo

JTopo-in-node & JTopo

最近实习公司一个项目需要绘制电网的拓扑图,大致要求的效果如下:
JTopo踩坑记 -- React项目中使用JTopo_第1张图片
首先想到的是Echarts和d3,因为这个项目其他图表都是使用的Echarts, 但是在Echarts的官方示例以及 Gallery中并没有找到类似的示例,并且Echarts的自动布局大多为环形布局,不符合项目需求。所以只能寻找其他的node包。然后就找到了JTopo,但是在官网上只有js文件,之后在npm官网找到了node版本的JTopo。需要说明的是,目前所有es6版本的JTopo相关的包都是由JTopo爱好者贡献的。一开始我只关注了JTopo这一个包, 但是在实际的使用中我发现了很多问题,并且很多JTopo官网有的功能这个包没有实现,这也导致我最终放弃了这个包, 而选择了JTopo-in-node。npm安装指令:

npm i jtopo-in-node

JTopo

JTopo这个包只是封装了一些基本的功能,比如创建node和link,虽然作者说的api和JTopo官网的类似,但是还是有一些差别的,比如官网给一个scene添加node或者link使用scene.add(node),但是在这个包中需要使用scene.name.add(node)。还有很多功能没有实现比如node的alarm以及tip只能在节点顶部绘制,无法显示link的名称;甚至还有一些错误,比如作者Github中给的vue写的示例,node的Tip显示会出错。在使用中我发现当canvas的大小超出了页面的高度,将页面滑动的时候会出现鼠标无法选择节点的情况,只有回到页面加载成功时的位置才能正常使用。

一开始我使用这个包进行开发,并且画出了大概的图JTopo踩坑记 -- React项目中使用JTopo_第2张图片
但是新的需求来了,需要平移和缩放以及查找节点。我发现没有继续使用这个包无法实现这个包。因为这个图上需要显示实时的数据,所以每一次有新的数据都会导致页面重绘,并且由于这个包没有提供自动布局,只能自己计算位置,所以新的需求没有办法实现,之后我就找到了jtopo-in-node。

jtopo-in-node

jtopo-in-node的api和JTopo官网几乎一样,可以参考官网的api教程,目前我只使用React实现了官网的一个实例:
JTopo踩坑记 -- React项目中使用JTopo_第3张图片
代码:

import React, { PureComponent } from 'react'
import JTopo from 'jtopo-in-node';
import {Row, Col, Card} from 'antd';

class DeviceGraph extends React.Component{
  state = {
    canvasWidth: '300',
    position: [],
    allSensors: []
  };
  componentDidMount() {
    var canvas = this.refs.test;
    canvas.width = window.innerWidth * 0.95;
    this.setState({
      canvasWidth: window.innerWidth * 0.95
    });
  }

  node = (scene, x, y, img) => {
    var node = new JTopo.Node();
    node.setImage('http://www.jtopo.com/demo/img/statistics/' + img, true);
    node.setLocation(x, y);
    node.dragable = false;
    node.fontColor = '0,0,0';
    scene.add(node);
    return node;
  };

  linkNode = (scene,nodeA, nodeZ, f) => {
    var link;
    if(f){
      link = new JTopo.FoldLink(nodeA, nodeZ, "test");
    }else{
      link = new JTopo.Link(nodeA, nodeZ);
    }
    link.direction = 'vertical';
    scene.add(link);
    return link;
  };

  hostLink = (scene, nodeA, nodeZ) => {
    var link = new JTopo.FlexionalLink(nodeA, nodeZ);
    link.shadow = false;
    link.offsetGap = 44;
    scene.add(link);
    return link;
  };

  render(){
    console.log('JTopo', JTopo);

    // canvas元素存在之后再进行操作
    if(this.refs.test){
      var stage = new JTopo.Stage(this.refs.test);
      stage.eagleEye.visible = null;
      stage.wheelZoom = 0.95;
      var scene = new JTopo.Scene(stage);
      scene.background = 'http://www.jtopo.com/demo/img/bg.jpg';

      var s1 = this.node(scene,305, 43, 'server.png');
      s1.alarm = '2 W';
      var s2 = this.node(scene,365, 43, 'server.png');
      var s3 = this.node(scene,425, 43, 'server.png');

      var g1 = this.node(scene,366, 125, 'gather.png');
      this.linkNode(scene,s1, g1, true);
      this.linkNode(scene,s2, g1, true);
      this.linkNode(scene,s3, g1, true);

      var w1 = this.node(scene,324, 167, 'wanjet.png');
      this.linkNode(scene,g1, w1);

      var c1 = this.node(scene,364, 214, 'center.png');
      this.linkNode(scene,w1, c1);

      var cloud = this.node(scene,344, 259, 'cloud.png');
      this.linkNode(scene,c1, cloud);

      var c2 = this.node(scene,364, 328, 'center.png');
      this.linkNode(scene,cloud, c2);

      var w2 = this.node(scene,324, 377, 'wanjet.png');
      this.linkNode(scene,c2, w2);

      var g2 = this.node(scene,366, 411, 'gather.png');
      this.linkNode(scene,w2, g2);

      var h1 = this.node(scene,218, 520, 'host.png');
      h1.alarm = '';
      this.hostLink(scene,g2, h1);
      var h2 = this.node(scene,292, 520, 'host.png');
      this.hostLink(scene,g2, h2);
      var h3 = this.node(scene,366, 520, 'host.png');
      h3.alarm = '二级告警';
      h3.text = 'h3';
      this.hostLink(scene,g2, h3);
      var h4 = this.node(scene,447, 520, 'host.png');
      this.hostLink(scene,g2, h4);
      var h5 = this.node(scene,515, 520, 'host.png');
      h5.alarm = '1M';
      this.hostLink(scene,g2, h5);

      stage.setCenter(515, 520)

      setInterval(function(){
        if(h3.alarm == '二级告警'){
          h3.alarm = null;
          h3.text = 'h3'+ Math.random()
        }else{
          h3.alarm = '二级告警'
        }
      }, 600);

    }

    return(
      
        
          
            
          
        
      
    )
  }

}

export default DeviceGraph;

没有安装antd的同学可以使用将render中的return换成

在控制台输出JTopo可以看到几乎实现了JTopo官网的所有功能:
JTopo踩坑记 -- React项目中使用JTopo_第4张图片
目前还没有用到项目当中,等到使用了之后再总结一下使用经验。

最后感谢JTopo原作者以及编写es6版本的爱好者,欢迎大家加入JTopo交流群:171820448 。

你可能感兴趣的:(React,JTopo,jtopo-in-node,拓扑图,React)