Implement pop-up box based on HTML5 Canvas

  When the user moves the mouse in, a pop-up box appears, which is very common. This is simple when dealing with HTML element implementation, but if you are dealing with graphics composed of HTML5 Canvas, this method is no longer applicable, because Canvas uses another set of mechanisms, no matter how many graphics are drawn on Canvas, Canvas is a overall. The graphics themselves are actually part of Canvas and cannot be obtained separately, so it is impossible to directly add JavaScript events to a graphic. However, in HT for Web , this requirement is easy to achieve, the scenarios are as follows:

  This scene graph is a JSON file based on HT for Web. You may have doubts about how to generate such a JSON file. In fact, it is based on the " HTML5 topology graph editor " ( http://www.hightopo ), which is small and complete. .com/demo/2deditor_20151010/HT-2D-Editor.html ) has been extended, and it is easy to customize a topology editor to meet my needs. Not only that, in this Demo, the three types of pop-up box vector 'tips1.json', 'tips2.json', 'tips3.json' are defined through this vector editor ( http://www.hightopo. com/demo/vector-editor/index.html ) is simply drawn, and it works just fine. In the above scenario, when the user moves the mouse into the grass and other objects, a pop-up box will display its detailed information, Demo address: http://www.hightopo.com/demo/blog_meadow_20170605/index.html

The specific implementation is as follows:

Ready to work

   Introducing our HT ( http://www.hightopo.com/ ):

<script src='ht.js'></script>

  

dataModel = new ht.DataModel();
graphView = new ht.graph.GraphView(dataModel);
graphView.addToDOM();

 

   HT provides a custom JSON format vector description format, which can also be registered and used as a picture in the JSON vector format defined by the HT standard. The HT vector format is more space-saving than the traditional format, and the scaling is not distorted. Click HT for Web Learn more. Here, three shapes of JSON pop-up boxes are registered as images for subsequent calls:

 

ht.Default.setImage('tips1', 'symbols/tips1.json');
ht.Default.setImage('tips2', 'symbols/tips2.json');
ht.Default.setImage('tips3', 'symbols/tips3.json');

 Then get the object with interactive effect, where the attribute name in each object is the label name set for each primitive: 

 

//Tree
var tree =
     'tree1' : true,
     'tree2' : true,
     'tree3' : true
};

//grassland
var grass = {
     'grass1' : true,
     'grass2' : true,
     'grass3' : true
 };
            
//Mountain
var mountain = {
    'mountain': true
};

 

pop-up windows

    In fact, the essence of the pop-up box is a Node. When the user moves the mouse in and out,

1. Control the hiding and display of Node to achieve the effect of a pop-up box;

2. The change of the mouse position is accompanied by the change of the Node position;

3. When the mouse is moved to different objects, the texture on the Node also changes accordingly;

4. The attribute value in Node also changes with the mouse position.

    Therefore, to realize the pop-up box, you should first create a new Node and set its level to 'higher'. Before that, you need to deserialize the JSON file of the scene graph, and set the deserialized primitives to Level 'lower' to prevent being blocked by existing primitives:

ht.Default.xhrLoad('meadow.json', function(text) {
    const json = ht.Default.parse(text);                    
    if(json.title) document.title = json.title;
    dataModel.deserialize(json);

    //set level
    dataModel.each(function(data){
        data.setLayer ('lower');
    });

    // create a new node
    var node = new ht.Node();                    
    node.s('2d.visible',false);
    node.setLayer ('higher');
    dataModel.add(node);

})

  然后,对底层的DIV监听mousemove事件,判断鼠标的位置是否在上述三个对象之上,根据对象类型,调用layout()函数对Node重新布局:

 

graphView.getView().addEventListener('mousemove', function(e) {
     node.s('2d.visible',false);
     var hoverData = graphView.getDataAt(e);
     pos = graphView.getLogicalPoint(e);
     if(!hoverData) return; 
     if(tree[hoverData.getTag()]){ 
        layout(node, pos, 'tips1');
     } else if (grass[hoverData.getTag()]) {
        layout(node, pos, 'tips2');
     } else if (mountain[hoverData.getTag()]) {
        layout(node, pos, 'tips3');
     }
});

  layout()函数所做的事情,已经在前面详细的阐述,其中,弹框中属性值的更新是将JSON文件的的text属性进行数据绑定,绑定的格式很简单,只需将以前的参数值用一个带func属性的对象替换即可,func的内容有一下几种类型:

1、function类型,直接调用该函数,并传入相关Data和view对象,由函数返回值决定参数值,即func(data, view);调用。

2、string类型:

      style@***开头,则返回data.getStyle(***)值,其中***代表style的属性名。

      attr@***开头,则返回data.getAttr(***)值,其中***代表attr的属性名。

      field@***开头,则返回data.***值,其中***代表attr的属性名。

      如果不匹配以上几种情况,则直接将string类型作为data对象的函数名调用data***(view),返回值作为参数值。

    除了func属性外,还可以设置value属性作为默认值,如果对应的func取得的值为undefined或者null时,则会采用value属性定义的默认值,详情可见HT for Web数据绑定手册http://www.hightopo.com/guide/guide/core/datamodel/ht-datamodel-guide.html)。例如,在这里,'tips1.json'文件中对阳光值进行数据绑定的结果如下:

 

"text": {
        "func": "attr@sunshine",
        "value": "阳光值"
      },

 下面贴上layout()函数的源代码:

function layout(node, pos, type){
                node.s('2d.visible',true);
                node.setImage(type);                   
                if(type == 'tips1'){
                    node.setPosition(pos.x + node.getWidth()/2, pos.y - node.getHeight()/2);
                    node.a({
                        'sunshine'  :   '阳光值   :     '+ (pos.x/1000).toFixed(2),
                        'rain'  :   '雨露值   :     '+ (pos.y/1000).toFixed(2),
                        'love'  :   '爱心值   :    ***'
                    });
                } else if(type == 'tips2'){
                    node.setPosition(pos.x , pos.y - node.getHeight()/2);
                    node.a({
                        'temp'  :   '温度   :     30',
                        'humidity'  :   '湿度   :     '+Math.round(pos.x/100)+'%'
                    });
                } else if(type == 'tips3'){
                    node.setPosition(pos.x - node.getWidth()/2, pos.y - node.getHeight()/2);
                    node.a({
                        'hight'  :   '海拔   :    ' + Math.round(pos.y)+'米',
                        'landscapes'  :   '地貌   :    喀斯特'
                    });
                }
            }

 

云移动

    最后,我们的Demo还有个云移动的动画效果,在HT的数据模型驱动的图形组件的设计架构下,动画可理解为将某些属性由起始值逐渐变为目标值的过程,HT提供了ht.Default.startAnim的动画函数,ht.Default.startAnim支持Frame-Based和Time-Based两种方式的动画:

   Frame-Based方式用户通过指定frames动画帧数,以及interval动画帧间隔参数控制动画效果;

   Time-Based方式用户只需要指定duration的动画周期的毫秒数即可,HT将在指定的时间周期内完成动画。

    详情见HT for Web。

    在这里我们用的是Time-Based方式,源码如下:

 

var cloud = dataModel.getDataByTag('cloud');
parent = dataModel.getDataByTag('mountain');
round1 = parent.getPosition().x - parent.getWidth()/2 + cloud.getWidth()/2;
round2 = parent.getPosition().x + parent.getWidth()/2 - cloud.getWidth()/2;
end = round1;

//云运动动画
var animParam = {
    duration: 10000,
    finishFunc: function() { 
         end = (end == round1) ? round2 : round1;
         ht.Default.startAnim(animParam);
    },
    action: function(v, t) {
         var p = cloud.getPosition();
         cloud.setPosition(p.x + (end - p.x) * v , p.y);
     }
};
ht.Default.startAnim(animParam);

  最后,再次放上我们的Demo,供大家参考。

 

 

 

 

 

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326615213&siteId=291194637