Skip to content

行为和脚本

jtopo提供了行为控制系统(behaviourSystem),可以将写好的脚本(函数)应用到指定的图元对象(Node、Link)上。

脚本定义

js
import {
    Stage,
    Layer,
} from '@jtopo/core';

// jtopo 的数据和脚本是分离,分别独立存在的
// 下面演示:1. 创建空场景 2. 加载 3. 执行脚本

// 1. 创建空的场景
const stage = new Stage('divId');
const layer = new Layer();
stage.addChild(layer);
stage.show();

// 事先准备好一个场景信息 (json数据可以通过编辑器或者序列化得到)
let sceneInfo = {
    // 数据(layer序列化的字符串)
    json: '{version":"2.4.0","Roots":[0],"Styles":......}';

    // 脚本 (函数的形式存在,两个入参: stage,layer, jtopo)
    script: function (stage, layer, jtopo) {
        // 脚本涉及到的对象引用通过 layer.querySelector()方法来获取 
        let leaderNode = layer.querySelector('[text="leader"]');
        let node = layer.querySelector('[name="myNode"]');

        // leaderNode 和 node 是同级,并非父子关系
    
        // 事件触发执行
        node.on('click', function(){
            node.text = 'clicked';
        });
    
        // 定义一个可复用的行为 : ‘将节点附着到另外一个节点的右上角’
        stage.behaviourSystem.defBehaviour('附着右上角', {
            // 初始化仅第一次执行
            first(node) {
                node.text = '';
            },
            // 每一帧绘制前执行
            update(node, context) {
                let leaderNode = context[0];

                // 计算leaderNode的右上角坐标,并修改node的xy
                node.x = leaderNode.x + leaderNode.width * 0.5;
                node.y = leaderNode.y - leaderNode.height * 0.5;
            }
        });

        // 行为执行时的’上下文环境‘
        let context = [leaderNode];

        // 为节点node对象添加一个名为 '附着右上角' 的行为控制 
        stage.behaviourSystem.addBehaviour(node, '附着右上角', context);
    }
}

// 2. 加载数据
layer.openJson(sceneInfo.json);

// 3. 运行脚本
layer.runScript(sceneInfo.script);

脚本序列化

从 2.4.0 版本开始:

序列化时:脚本可以在序列化时嵌入到json中了。
反序列化时:可以通过Runtime来执行, 如下示例:
js
import {Runtime} from '@jtopo/core';

// 三个入参:stage, layer, jtopo
function myScript(stage, layer, jtopo) {
    let fromNode = layer.querySelector('[name="fromNode"]');

    // 注意:此时是运行时,已经脱离了开发环境, 用过jtopo引用来访问各种类对象
    let node = new jtopo.Node('');
    layer.addChild(node);

    //....
}

// 序列化时把脚本代码嵌入json, 增加了info字段,可以增加画面的额外信息
const withScriptJson = layer.toFileJson({
    script: myScript.toString(),
    info: {
        author: 'Jack',
        date: '2020-01-01',
        description: 'XXX车间控制图-A'
        //...
    }
});

// 反序列化加载数据时
layer.openJson(withScriptJson).then((jsonObj)=>{
    // 执行脚本
    Runtime.execute(jsonObj.script, layer);
});