渲染元素可以是html dom对象,也可以是ht对象,甚至仅做逻辑不return返回!渲染元素模板,以及设置渲染元素是否编辑状态随着图纸也矢量缩放;内置拖放矢量基本组件类型;监听数据绑定的变量属性变化

矢量手册 - HT for Web

1. 本质分析

通过定义HT矢量JSONrenderHTML函数属性,可实现在GraphView拓扑图上,嵌入任意第三方HTML DOM元素。HT的图纸是Canvas实现,renderHTMLDOM一定在Canvas之上,使用renderHTMLDOM与常规Canvas上绘制的图元不可能有层级控制可能性。

简言之,渲染元素只是在canvas相应位置在其上层叠放一个div方块,位置和大小就是编辑的ht.Node区域,这个图元是随时可以拖拽编辑的,任何属性的变化都会通知渲染元素代码执行重绘,不管是内部逻辑属性更新,还是位置、大小随编辑的ht.Node变化!从效果上来看,感觉就是html div就成了canvas图元可以被编辑,其实从来都没有成为过图元,只是图元上面的一把遮阳伞!

因此渲染元素dom与canvas上的某个图元参与层级控制是不可能的,canvas本身就是一个整体,如果要参与层级控制,那么canvas与其他多个渲染元素才是一个维度能参与层级控制的!

2. 精简模板

JavaScript
if (!cache.obj) {
    
    //【类型Ⅰ】:HT对象用new
    var obj = cache.obj = new ht.ui.TextField();               
    
    //【类型Ⅱ】:html dom对象用document.createElement
    //var obj = cache.obj = document.createElement('iframe');    
    
    
    // TODO,属性暴露,界面创建、事件监听处理等等逻辑
    
    
    obj.layoutHTML = function () {
        gv.layoutHTML(data, obj, false);   //参数true,保持运行状态,不会随编辑缩放;
                                           //传入false,编辑器中也跟矢量图一样能缩放!
                                           //html dom的放大会模糊;ht组件对象如果没有设置
                                           //矢量缓存,也会矢量清晰,设置了缓存的也会变模糊!
    }
}

return cache.obj;

3. 推荐模板

JavaScript
if (!cache.obj) {
    function init() {
        var myview = new ht.ui.TextField(); 

        //TODO
        
        return myview;
    }

    var obj = cache.obj = init()
    
    obj.layoutHTML = function () {
        gv.layoutHTML(data, obj, false);
    }
}

/*渲染元素组件通用配置属性*/
//shadowBorder:[0,0,8];shadowColor:rgba(102,102,102,0.2)
initShadow(cache.obj,data.ca('shadowBorder'),data.ca('shadowColor'),data.ca('shadowEnabled'));
    
return cache.obj;

ht渲染元素支持返回html DOM对象,以及HT对象,其中模板里面

对于ht提供的代码界面demo示例,想要放到编辑器中可拖拽配置的,可以通过作为渲染元素的方式实现,并且代码改动非常少,常规ht代码示例如下:

[该类型的内容暂不支持下载]

HTML
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Alarm on tree</title>
<!------------------依赖的特舒插件,指定增量合并打包到htiotos.js中即可---------->
        <script src="../../../../lib/core/ht.js"></script>
        <script src="../../../../lib/plugin/ht-telecom.js"></script>    
<!-------------------------------------------------------------------------->
        <script>

//----------------------以下整个拷贝到图标的渲染元素内-------------------------
            var dataModel = new ht.DataModel();
            var graphView = new ht.graph.GraphView(dataModel);
            var treeView = new ht.widget.TreeView(dataModel);
            var splitView = new ht.widget.SplitView(treeView, graphView, 'horizontal', .3);

            function init() {  //ht demo示例基本都是init()函数开头不动!
                               //在上述模板中就是 var obj = cache.obj = init()
                // Add circle at left bottom corner represented new alarm
                initTreeIcon();

                // Enable AlarmStatePropagator
                dataModel.setEnableAlarmStatePropagator(true);

                // Add Group
                var group = new ht.Group();
                group.setExpanded(true);
                group.setName('Group');
                dataModel.add(group);

                // Iterate HT default AlarmSeverity, add node with related AlarmSeverity
                var x = -50, y = 100;
                ht.AlarmSeverity.each(function (severity) {
                    var node = new ht.Node();
                    node.setName(severity.name);
                    node.setPosition(x += 100, 100);
                    node.getAlarmState().increaseNewAlarm(severity);
                    group.addChild(node);
                    dataModel.add(node);
                });

                // Expand all tree nodes
                treeView.expandAll();

                // Add spliteView to document body
                splitView.addToDOM(); //在init()内找到调用addToDoM的这句,需要屏蔽掉,并且return该对象即可!
            }

            function initTreeIcon() {
                ht.Default.getImage('__alarmIcon__').comps.push({
                    type: 'circle',
                    gradient: 'radial.center',
                    gradientColor: '#FFFFFF',
                    background: {
                        func: function (data) {
                            var severity = data.getAlarmState().getHighestNewAlarmSeverity();
                            if (severity) {
                                return severity.color;
                            }
                            return null;
                        }
                    },
                    visible: {
                        func: function (data) {
                            return !!data.getAlarmState().getHighestNewAlarmSeverity();
                        },
                    },
                    rect: [1, 8, 8, 8]
                });
            }
//-------------------------------------------------------------------------------

        </script>
    </head>
    <body οnlοad="init();">
    </body>
</html>

对应的渲染元素代码如下,红底为固定模板代码,黄色背景为修改的demo代码,不变的就是ht demo直接拷贝过来的):,可见对于固定ht对象界面代码,固定模板下,拷贝demo过来只需要屏蔽一句随后return返回对象即可,改动仅此两点(此外可能就涉及插件需要增量htiotos.js)!

JavaScript
if (!cache.obj) {

           var dataModel = new ht.DataModel();
            var graphView = new ht.graph.GraphView(dataModel);
            var treeView = new ht.widget.TreeView(dataModel);
            var splitView = new ht.widget.SplitView(treeView, graphView, 'horizontal', .3);

            function init() {
                // Add circle at left bottom corner represented new alarm
                initTreeIcon();

                // Enable AlarmStatePropagator
                dataModel.setEnableAlarmStatePropagator(true);

                // Add Group
                var group = new ht.Group();
                group.setExpanded(true);
                group.setName('Group');
                dataModel.add(group);

                // Iterate HT default AlarmSeverity, add node with related AlarmSeverity
                var x = -50, y = 100;
                ht.AlarmSeverity.each(function (severity) {
                    var node = new ht.Node();
                    node.setName(severity.name);
                    node.setPosition(x += 100, 100);
                    node.getAlarmState().increaseNewAlarm(severity);
                    group.addChild(node);
                    dataModel.add(node);
                });

                // Expand all tree nodes
                treeView.expandAll();

                // Add spliteView to document body
                //splitView.addToDOM();
                return splitView
            }

            function initTreeIcon() {
                ht.Default.getImage('__alarmIcon__').comps.push({
                    type: 'circle',
                    gradient: 'radial.center',
                    gradientColor: '#FFFFFF',
                    background: {
                        func: function (data) {
                            var severity = data.getAlarmState().getHighestNewAlarmSeverity();
                            if (severity) {
                                return severity.color;
                            }
                            return null;
                        }
                    },
                    visible: {
                        func: function (data) {
                            return !!data.getAlarmState().getHighestNewAlarmSeverity();
                        },
                    },
                    rect: [1, 8, 8, 8]
                });
            }

    var obj = cache.obj = init()
    
    obj.layoutHTML = function () {
        gv.layoutHTML(data, obj, false);
    }
}

return cache.obj;

注意,渲染元素也可以不做任何模板,不进行dom或ht ui视图组件对象实例化,可以只对data进行属性暴露处理,用以更多属性在组态图纸编辑上可配置,而不是用来展现扩展的自定义拖拽组件:

【重要】代码操作组态界面图元对象;组态展示代码创建的对象;ht示例代码图元对象视图与组态图纸界面融合;代码对象以html dom元素添加到组态以及CSS控制;以ht.Grid为例用渲染元素暴露属性可配置(尤其派生类图元)

对于渲染元素编写模板中,需要一个优化的地方,那就是当代码比较复杂、组件属性暴露较多需要考虑多方面性能时,需要调整下代码结构,监听data.dm()数据模型中所有属性变量的变化,是当前图元的指定属性attr变化才执行数据动态刷新函数:

JavaScript
if (!cache.obj) {
    function init() {
        let splitLayout = new ht.ui.SplitLayout();
        //……
        
        /*想要能在指定的变量变化时动态执行改代码,实现所见即所得编辑及
        数据驱动即时刷新,原本直接写代这里一次性初始化执行的代码,改成函数
        需要图纸中动态配置实时变化的,放到局部的函数体内便于动态调用*/
        function initRows(){
            //……
        }
      
        /*初始调用一次*/
        initRows();                                 //初始化调用
        
        /*【重要】监听DataModel下所有图元,指定某个属性变化,触发执行上面封装的函数:*/
        data.dm().md(e => {
            if(e.data == data){
                // //event格式:
                // {
                //     property: 'name',//发生变化的属性
                //     oldValue: 'oldValue',//旧值
                //     newValue: 'newValue',''新值
                //     data: data//发生变化的data
                // }
                switch(e.property){//某数据绑定变量的变化事件
                    case:'a:datas'
                        initRows();//调用局部函数动态刷新   
                        break;              
                }
            }
        })
        return splitLayout
    }

    var obj = cache.obj = init()

    obj.layoutHTML = function() {
        gv.layoutHTML(data, obj, false);
    }
}

//……

return cache.obj;

4. 更新模板

JavaScript
if (!cache.obj) {
    function init() {
        var control= new ht.ui.TextField(); 
        
        /*输入框等部分属性需要数据双向绑定,所以还需要加上这里的通用处理,实现代码中API对属性
        值的操作改变,能同步影响到图纸中暴露的数据变量!与dm监听属性变化处理呼应,这样API对组件
        的赋值,就能同步到界面配置数据变化关联的其他逻辑上!*/
        control.on('p:value',v => {
            data.ca('value',v.newValue);//重点是这句!回写到数据绑定的变量上!
            if(v.oldValue == undefined || v.newValue != v.oldValue){//值变化才触发调用
                let cb = new Function('return ' + data.a('onChange'))()
                return cb && cb(data,v.newValue)
            }
        })

        //TODO
        function initXXX(){                    
        
        }
        
        data.dm().md(e => {
            if(e.data == data){
                // //event格式:
                // {
                //     property: 'name',//发生变化的属性
                //     oldValue: 'oldValue',//旧值
                //     newValue: 'newValue',''新值
                //     data: data//发生变化的data
                // }
                switch(e.property){
                    case 'a:datas':
                        initXXX();   
                        break;
                    case 'a:loadStyle':
                        //……
                        break;
                    case 'a:rightSide':
                        //……
                        break;
                    case 'width':    //对于p:width等属性,就不需要带a:、p:了!!
                        break;
                }
            }
        })
        
        initXXX();                            
        return control;
    }

    var obj = cache.obj = init()
    
    obj.layoutHTML = function () {
        gv.layoutHTML(data, obj, runningMode());
    }
}

//shadowBorder:[0,0,8];shadowColor:rgba(102,102,102,0.2)
initShadow(cache.obj,data.ca('shadowBorder'),data.ca('shadowColor'),data.ca('shadowEnabled'));

return cache.obj;

【附】渲染元素通用属性配置对应的数据绑定变量定义,可用于批量复制粘贴:

JSON
{
  "attr": "shadowBorder",
  "valueType": "NumberArray",
  "defaultValue": [
    0,
    0,
    8
  ]
},
{
  "attr": "shadowColor",
  "valueType": "Color",
  "defaultValue": "rgba(102,102,102,0.2)"
},
{
  "attr": "shadowEnabled",
  "valueType": "Boolean",
  "defaultValue": false
},

以下是渲染元素中代码只做逻辑,不做任何组件渲染return的两个示例,分别是在持续高频刷新的情况下通过标记来让执行依次,以及通过dm事件监听特定属性变化才执行逻辑!

注意,渲染元素做逻辑可以有非常多的用途,可以代替图标中嵌套图元、组件属性的func函数过滤,可以对图标中数据绑定的变量任意做逻辑处理,实现具备一定业务场景代码封装的图标,各个属性之间除了用户手动配置,还有一定的代码自动化逻辑处理:

以下代码可以直接粘贴到渲染元素的代码编辑窗口内,不需要通常模板中的if(!cache.obj)、return等

逻辑模板(常规)

JavaScript
if(data.ca('darkStyle')){
    if(cache.init == undefined){
        cache.init = 'done'
        cache.borderColor = data.ca('ht.borderColor')
        cache.textColor = data.ca('ht.textColor')
        cache.background = data.ca('ht.background')
    }else{
        data.ca('ht.borderColor',cache.borderColor)
        data.ca('ht.background',cache.background)
        data.ca('ht.textColor',cache.borderColor)
    }
}else{
    if(cache.init == undefined){
        cache.init = 'done'
        cache.borderColor = data.ca('ht.background')
        cache.textColor = data.ca('ht.background')
        cache.background = data.ca('ht.borderColor')
    }else{
        data.ca('ht.borderColor',cache.background)
        data.ca('ht.background',cache.borderColor)
        data.ca('ht.textColor',cache.background)
    }
}

5. 逻辑模板(推荐)

JavaScript
if(!cache.init){
    cache.init = 'done'
    data.dm().md(e => {
        if(e.data == data){
            // //event格式:
            // {
            //     property: 'name',//发生变化的属性
            //     oldValue: 'oldValue',//旧值
            //     newValue: 'newValue',''新值
            //     data: data//发生变化的data
            // }
            switch(e.property){
                case 'a:ht.background':
                    break;
                case 'a:ht.borderColor':
                    data.ca('ht.textColor',e.newValue);
                    break;
                case 'a:ht.textColor':
                    data.ca('ht.borderColor',e.newValue);
                    break;
                case 'a:darkStyle':
                    let colortmp = data.ca('ht.textColor');
                    data.ca('ht.borderColor', data.ca('ht.background'));
                    data.ca('ht.textColor', data.ca('ht.background'))
                    data.ca('ht.background', colortmp);
                    break;
            }
        }
    })
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IOTOS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值