首页 > 其他分享 >js实现自定义网络拓扑图-实战记录

js实现自定义网络拓扑图-实战记录

时间:2023-01-30 12:11:29浏览次数:55  
标签:node Node layer 自定义 js var new 网络拓扑 stage

首先推荐工具库JTopo: jtopo 一个好用的交互式HTML5图形库

其他的看官方文档

 

 

 

 

 

 

 

 

 

 

 

 

三、基础讲解

jtopo的核心对象有Stage、Layer、Canvas、Node、Link, 关系如下图:

Stage、Layer和Node关系

顶层对象(Stage)

jtopo的核心对象之间存在层级结构,最顶层的为Stage,管理一个或者多个Layer,可以对Layer进行管理:添加、移除。

提供一些常规性的交互功能,比如:鼠标缩放、视图模式变换(普通、框选、拖拽、编辑、锁定);

显示控制:按画布居中、1:1显示 导出图片等功能。

代码示例:

    var stage = new Stage(“divId”);
    stage.show(); // 显示出来

详细的:Stage-API参考

层对象(Layer)

Layer 是一个抽象对象,默认是完全透明的,上层对象为Stage.

一个Layer下面可以有多个Node、Link对象,Node、Link对象只有放入Layer后才可能被绘制出来。

Layer 可以被平移、缩放,用户可以通过鼠标在画布上的拖拽 和 鼠标滚轮完成,也可以通过API来修改Layer的x、y坐标和缩放系数scaleX和scaleY实现同等效果。

一个Layer对象对应一个Canvas,多个Layer常用于画面逻辑分层,比如有的层绘制速度较慢,有的层绘制速度较快,有的层作为背景层,有的作为动画层。

代码示例:

    var stage = new Stage();
    var layer = new Layer(“layer-1”);
    stage.addChild(layer); // 放入Stage
    //…
    stage.show(); // 显示出来

详细的:Layer-API参考

节点对象(Node)

用户操作的核心两个对象Node 、Link之一。

Node给人的形象是一个矩形,有坐标(x,y) 和 宽高尺寸(width、heigh)。

可以指定一个文本字符串,默认显示在中矩形的下面。

Node对象的外观可以通过css方法设置,核心的外观属性有:边框颜色、填充颜色、字体颜色、字体(大小、加粗等CSS Font支持的都可以)、圆角。

代码示例:

    var stage = new Stage();
    var layer = new Layer(“layer-1”);
    stage.addChild(layer); // 放入Stage

    var node = new Node(“Node-1”);
    layer.addChild(node); // 放入Layer

    stage.show(); // 显示出来

各种Node效果如下:

参考:Node演示

详细的:Node-API参考

连线对象(Link)

用户操作的核心两个对象之一。

Link给人的形象是连线,有起始点和结束点,一般用来表示关系、流向等。

可以指定一个文本字符串,默认显示在连线的中间。

Link对象的外观可以通过css方法设置,核心的外观属性有:颜色、线条粗细、字体颜色、字体(大小、加粗等CSS Font支持的都可以)。

代码示例:

    var link = new Link('Link',fromNode,toNode);
    layer.addChild(link);

各种Link效果如下:

参考:Link演示 详细的:Link-API参考

外观样式(Style)

样式大部分属性命名和效果都遵循和参考了Html5-css。

var stage = new Stage('divId');
var layer = new Layer('default');
stage.addChild(layer);


// 样式大部分属性命名和效果都遵循Html5-Canvas的绘图定义
// 其本质是:绘制每个图元前 去修改Canvas 绘图环境context的属性

// 父节点只有某些属性可以影响到子节点(例如全局性的阴影、字体、
// 某些子节点的样式为空的时候父样式才可能生效)

// 全局字体
layer.css({
    // 字体,格式CSS-FONT
    'font': 'bold 12px 仿宋',
});

let circleNode = new CircleNode('节点', 60, 300, 100);

// 可以用类似css语法设置更多属性, 涉及语法详细可以参考CSS相关教程。
circleNode.css({
    width: 48,
    height: '48px',
    border: 'solid 1px gray',
    borderRadius: 5,
    background: "white url('./demo/img/node2.png') no-repeat",
    backgroundSize: '32px 32px',
    backgroundPosition: 'center center',
    zIndex: 2,
    font: 'bold 11px arial',
    color: 'gray',
    textPosition: 'center', // 位置
    textAlign: 'center',    // 左右居中
    textBaseline: 'middle'     // 上下居中
});
layer.addChild(circleNode);


stage.show();

事件处理(鼠标交互)

jtopo封装了鼠标行为,可以在Node或者Link对象上增加事件监听,代码示例:

var stage = new Stage('divId');
var layer = new Layer('default');
stage.addChild(layer);

var node = new Node('From', 200, 150, 40, 40);
node.setImage('./demo/img/laptop.png', true);
layer.addChild(node);

stage.show();

// 鼠标点击
node.on('click', function (event) {
    // 更详细的事件信息,
    // 比如:鼠标在画布上的x,y坐标, 鼠标状态(是否拖拽开始、结束), 相对于上一次鼠标位置的偏移量(dx,dy)等
    let eventDetails = event.details;

    node.text = 'click';
    console.log('click');
});

// 鼠标双击
node.on('dblclick', function (event) {
    console.log('dblclick');
    node.text = 'dblclick';
});

// 鼠标进入
node.on('mouseenter', function (event) {
    console.log('mouseenter');
    node.text = 'mouseenter';
});

// 鼠标移动
node.on('mousemove', function (event) {
    console.log('mousemove');
    node.text = 'mousemove';
});

// 鼠标离开
node.on('mouseout', function (event) {
    node.text = 'mouseout';
    console.log('mouseout');
});

// 鼠标按下
node.on('mousedown', function (event) {
    console.log('mousedown');
    node.text = 'mousedown';
});

// 鼠标松开
node.on('mouseup', function (event) {
    console.log('mouseup');
    node.text = 'mouseup';
});

// 鼠标拖拽
node.on('mousedrag', function (event) {
    console.log('mousedrag');
    node.text = 'mousedrag';
});

// 鼠标拖拽结束
node.on('mousedragend', function (event) {
    console.log('mousedragend');
    node.text = 'mousedragend';
});


node.on('touchstart', function (event) {
    node.text = 'touchstart';
});

node.on('touchmove', function (event) {
    node.text = 'touchmove';
});

node.on('touchend', function (event) {
    node.text = 'touchend';
});

// --- 下面是较为高级的事件处理示例
// 阻止默认拖拽处理, 参考:Html事件的preventDefault() 说明
function preventDefaultDrag(e) {
    e.preventDefault();
}

function disabledDefaultMouseDragHandler(obj) {
    obj.on('mousedrag', preventDefaultDrag);
}

function enabledDefaultMouseDragHandler(obj) {
    obj.removeEventListener('mousedrag', preventDefaultDrag);
}

// 阻止默认拖拽处理
node.on('mousedrag', preventDefaultDrag);

// 定义自己的拖拽处理
function customDragHandler(event) {
    // 每次拖拽偏移量
    console.log(event.dx + ' - ' + event.dy);
    //....

    // 还可以再次抛出自己的事件
    node.dispatchEvent(new Event('myEvent'));
}
// 使用自己的事件处理 (on 等价 addEventListener,简写而已)
node.on('mousedrag', customDragHandler);

// 捕获自己抛出的自定义事件
node.on('myEvent', function (event) {
    console.log('我的事件');
    console.log(event);
});

// 恢复默认拖拽
node.removeEventListener('mousedrag', preventDefaultDrag);

// 删除自己的拖拽处理
node.removeEventListener('mousedrag', customDragHandler);

参考:事件处理演示

父子关系

Node和Link都有parent 和 children 属性
    //...

    layer.removeAllChild();     // 清空
    layer.children.length == 0; // true

    let node = new Node();
    layer.addChild(node);        // node.parent === layer -> true
    layer.chidlren[0] === node;  // true node 在 layer.chidlren集合里

    //...
    layer.addChild(node2); 
    layer.addChild(link3); 

    // 此时node、node2 和 link3 的 parent相同

zIndex

zIndex用来控制前后遮挡关系(同父类下的直接子节点之间有效).

数值越大越靠前面,越小越靠后,前面会遮挡后面。

Node 和 Link 默认的zIndex值分别为 2  和 1, 所以默认同层的Node遮盖Link。
    // 示例 :
    fromNode.zIndex = 3;
    toNode.zIndex = 4;
    link.zIndex = toNode.zIndex + 1;

动画



var stage = new Stage('divId');
var layer = new Layer();
stage.addChild(layer);

var node = new Node('动画演示', stage.width / 2 - 100, stage.height / 2 - 100, 100, 100);
node.css({
    'borderColor': 'black',
    'textPosition': 'center',
});
layer.addChild(node);

// 在6000毫秒内,n从0逐渐变为2*Math.PI
let animation = new Animation(0, 2 * Math.PI, 6000, function (n) {

    // 旋转
    node.rotateTo(n);

    // 重绘
    layer.update();
});

// 播放
animation.play().then(() => {
    node.text = '正常结束';
}).catch(() => {
    node.text = '终止或结束';
});

// 暂停
node.on('mouseenter', () => {
    animation.pause();
});

// 继续
node.on('mouseout', () => {
    animation.continue();
});

// 停止
node.on('click', () => {
    animation.stop();
});

// 播放
node.on('dblclick', () => {
    animation.play();
});

stage.show();

参考:动画演示 详细的:Animation-API参考

四、布局

布局功能允许用户把Node和Link按照一定形式调整相对坐标

网格布局(GridLayout)

网格布局是较为简单的一种布局,把Node对象按照行、列的方式摆放

// 存放要布局的节点数组
var nodes = [];

// 生成9个节点
for(var i=0; i<9; i++){
    var node = new Node(''+i, 0,0,32,32);
    nodes.push(node);
}

// 网格式布局
var layout = new GridLayout(rows, cols);

// 节点间隔
layout.setMargin(40, 40, 0, 0);

// 动画时间, 毫秒, 不设置,就没有动画效果.
layout.setTime(1500);

// 布局的每一步回调(这里是刷新画面)
layout.onLayout(() => layer.update());

// 布局后的中心
// 布局后的中心点
layout.setCenter(stage.width * 0.5, stage.height * 0.5);

// 执行布局
gridLayout.doLayout(nodes).then(=> {
    // 布局执行结束
});

效果:

参考:网格布局演示

详细的:GridLayout-API参考

树形布局(TreeLayout)

树形布局根据Node和Link的关系自动找到根节点,然后递归式的逐级布局为一棵树的形状。 可以指定树的朝向。


let objects = []; // Node和Link组成的集合

// 方向: up、down、left、right
// 左右间隔量 40, 上下间隔量 80
var layout = new TreeLayout('down');
layout.setMargin(0, 50, 80);

// 动画时间, 毫秒, 不设置,就没有动画效果.
layout.setTime(1200);

// 布局的每一步回调(这里是刷新画面)
layout.onLayout(() => layer.update());

// 布局后的中心
layout.setCenter(stage.width * 0.5, stage.height * 0.5);

// 生成虚拟树,取第一棵
let vTrees = new Graph(objects).toTrees();
let vTree = vTrees[0];

// 执行布局
layout.doLayout(vTree).then(() => {
    // 结束
});

效果:

参考:树形布局演示

详细的:Layer-API参考

流式布局(FlowLayout)

圆形布局将多个节点以圆形进行布局。

var stage = new Stage('divId');
var layer = new Layer();
stage.addChild(layer);
layer.css({
    'shadowColor': '#E0E0E0',
    'shadowBlur': 7,
    'shadowOffsetX': 2,
    'shadowOffsetY': 2,
    'font': 'bold 10px arial'
});

const nodes = [];
// 随机生成节点
for (var i = 0; i < 20; i++) {
    var node = new Node('' + i);
    node.resizeTo(32 + (50 * Math.random()),
     32 + (50 * Math.random()));
    node.textOffsetY = 2;
    node.x = stage.width * Math.random();
    node.y = stage.height * Math.random();
    node.css({
        'borderColor': null, // 无边框 
        'backgroundColor': randomColor()
    });
    nodes.push(node);
    layer.addChild(node);
}
stage.show();

// 流式布局
var layout = new FlowLayout();

layout.setSize(500);

// 动画时间, 毫秒, 不设置,就没有动画效果.
layout.setTime(1000);

// 节点间隔
layout.setMargin(0, 3);

// 布局的每一步回调(这里是刷新画面)
layout.onLayout(() => layer.update());

// 布局后的中心点
layout.setCenter(stage.width * 0.5, stage.height * 0.5);

// 布局, 结束后调整尺寸再次布局, 反复几次
layout.doLayout(nodes);

效果:

标签:node,Node,layer,自定义,js,var,new,网络拓扑,stage
From: https://www.cnblogs.com/zifayin/p/17075092.html

相关文章

  • 如何从json数据中提取数据
        //将数据解析成json格式var data=JSON.parse(responseBody);//获取id值var procInstId=data.data.id; var workId=data.data.works[0].id;pm.envir......
  • 用html2canvas.js 将前端HTML页面生成图片
    首先去html2canvas官网下载html2canvas.js文件html2canvas官网地址:http://html2canvas.hertzen.com/HTML<divid="host_file"class="container"><divid="view"c......
  • nodejs 安装多版本 版本切换
    版权声明:本文为博主原创文章,遵循CC4.0BY-SA版权协议,转载请附上原文出处链接和本声明。本文链接:https://blog.csdn.net/qq_40127119/article/details/128450398————......
  • Date.parse() js 快速将日期格式转换为时间戳
    参考自文档:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Date/parseDate.parse()Date.parse()方法解析一个表示某个日期的字......
  • SAP UI5 应用的标准 Theme 和自定义 Theme 的加载讨论
    SAPUI5应用的初始主题可以硬编码在应用程序中(在加载SAPUI5的引导程序的脚本标签中)或在加载SAPUI5之前定义的JS配置对象中,例如下面的例子:<scriptid="sap-ui-boots......
  • Js学习之 ----- 冒泡排序
    用最直观的举例:把数组:[7,6,5,4,3,2,1]从小到大排序【从小到大】冒泡排序的关键:每一轮,把相邻元素进行比较,把最大的元素排到最后下一轮,进行相同的操作,最后的元素不用再......
  • nvm安装和管理nodehjs
    一、NVM简介NVM全称NodeVersionManager,是一个管理NodeJS版本的工具。NVM默认只支持Linux和OSX,不支持Windowswindows使用nvm-windows(https://github.com/cor......
  • ExtJS-组件查询
    更新记录点击查看>2023年1月6日更新Ext.getCmp>2022年12月3日开始。ExtJS教程汇总:https://www.cnblogs.com/cqpanda/p/16328016.htmlFindingcomponentsbase......
  • 富文本编辑器 quill.js 开发(二): 光标和选区
    术语表首先我们需要知道一些术语,才能更好地理解,如果您已经了解,可以跳过这一段锚点(anchor)锚指的是一个选区的起始点(不同于HTML中的锚点链接)。当我们使用鼠标......
  • vue.js客服系统实时聊天项目开发(十一)处理发送消息enter事件以及实现ctrl+enter换行
    当我们的在线客服系统,输入框发送消息的时候,可以直接回车发送消息,并且要支持ctrl+enter是换行操作那么我们的html事件部分是这样写<textareaclass="chatAreaInput"v-mo......