3D interactive visual display of the periodic table of elements, a programmer’s student memoir

Preface

I saw articles about the periodic table written by others on the Internet before, which deeply evoked a wave of memories. In my memory, I remembered "hydrogen, helium, lithium, helium, boron, carbon, nitrogen, oxygen, fluorine, neon, sodium magnesium aluminum silicon phosphorus, Sulfur, Chlorine, Argon, Potassium and Calcium", "Raise (oxygen) turtle (silicon), aluminum iron cover (calcium), which (sodium) home (potassium) does not (magnesium) green (hydrogen) vegetable (titanium)", the quality recorded in high school Conservation, conservation of elements, conservation of atoms, conservation of electrons, time passes so fast, we are all so big in a blink of an eye.

I have nothing to do with my programmer colleagues when I was studying the periodic table of elements during my student days. My programmer colleagues decided to use  HT  to make a visual display of the periodic table. HT has 2D topology and 3D model scenes. Both forms of sharing are realized this time, so let's take a look~

Interface display

The entire page is composed of HT UI components, using the ht.ui.TabLayout tab layout components to display the 23D interface separately.

2D interface: The whole is a ht.ui.SplitLayout split component (left and right split), the left side uses ht.ui.HTView to wrap the GraphView topology diagram component, and the right side is a ht.ui.Form form component.

Memoirs of a programmer’s student days: 3D interactive visualization of the periodic table

Dynamic preview address: https://www.hightopo.com/demos/index.html

3D interface: The whole is a ht.ui.SplitLayout split component (up and down), the button group composed of ht.ui.HBoxLayout is added on the top, and the Graph3dView scene is wrapped with ht.ui.HTView on the bottom.

Memoirs of a programmer’s student days: 3D interactive visualization of the periodic table

 

Overall video presentation:

 

 

2D interface code analysis

Topology diagram component

Let’s first talk about the topology graph component on the left. ht.graph.GraphView  is the most abundant 2D component in the HT framework. It has basic graphics presentation and editing functions, topology node connection and automatic layout functions, and is pre-defined in the power and telecommunications industries. The object has special effects such as animation rendering, so it has a wide range of applications. It can be used as a drawing tool and man-machine interface in the monitoring field, as a general graphical editing tool, and can be extended to enterprise applications such as workflow and organization chart.

Each of the 118 elements displayed in the topology diagram is a ht.Node topology node. The default node display is a small computer style. Here we set the image information displayed by the node through setImage, as shown below:

Memoirs of a programmer’s student days: 3D interactive visualization of the periodic table

 

Vector illustration

The graphics are described by points, lines, and polygons, so the same accuracy can be maintained even when the picture is infinitely enlarged and reduced. The above picture is a vector diagram, which is composed of 1 rectangle and 6 texts. It can be zoomed and scaled arbitrarily without distortion. You can visit the demo address and use the scroll wheel to zoom in and out of the topology for experience. Please refer to the vector manual for drawing the specific vector diagram.

Some people will definitely have questions about whether to draw 118 vector diagrams for the 118 elements. It feels slightly acceptable. If there are thousands of them, then people will get tired. Don’t be afraid, HT  helped us solve this problem by data binding the drawn vector diagram and binding the properties of the drawn content to the properties of the node. In the application, by updating the corresponding properties of the node, the graphical interface will automatically refresh to achieve The effect of displaying data in real time. For example, in this vector diagram of mine, I data-bound the text content and font color of the 6 element attributes and the background color of the rectangle. After binding, I only need to pass node.a('background ','#FEB64D') you can modify the background color of the rectangle (backgrouond is the property bound to the background color of the rectangle), please refer to the data binding manual for specific data binding.

Now that we talked about data binding, let's first look at the function of displaying element classification, as shown in the figure below. The change of node style is not to set another vector map by resetting setImage, but to modify the style attributes bound in the original vector. According to the category of the element, modify the rectangle background color of the vector diagram and the text color of the element Chinese name. The button to switch states is the ht.ui.ToggleButton switch button, which has two states of "0/1". By monitoring whether the button is selected, you can switch the periodic table style.

toggle.on('p:selected', e => {
    if (e.newValue) {
        this.htView.legend.s('2d.visible', true); // 显示类别图例
        this.htView.addClassification(); // 展示分类
    }
    else {
        this.htView.legend.s('2d.visible', false); // 隐藏类别图例
        this.htView.initElements(); // 原始样式
    }
});

Memoirs of a programmer’s student days: 3D interactive visualization of the periodic table

 

Memoirs of a programmer’s student days: 3D interactive visualization of the periodic table

 

The legend of the element category is also a ht.Node node, which is also a drawn vector. It is in the drawing from the beginning. Node.s('2d.visible', false) is set to invisible. When you want to display the category, set it to true is displayed.

Memoirs of a programmer’s student days: 3D interactive visualization of the periodic table

 

Form panel

The form panel on the right has 5 rows, the second row is the display classification function mentioned above, and the third row is a text input box used to obtain the ordinal number of the element, which limits only the number of input, and also adds the verification of the input number. Only 1~118 can be entered.

code show as below:

let textField = new ht.ui.TextField();
textField.setFormDataName('textField'); // 设置在表单中的名称
textField.setPlaceholder('请输入查询的元素序数!');
textField.setMaskRe(/\d/); // 限制只能输入数字
textField.setInstant(true); // 开启即时模式,值改变就派发属性改变事件
textField.on('p:value', (e) => { // 监听值改变事件
    let value = e.newValue;
    if (value > 118) {
        textField.setErrorMessage('只有 1 ~ 118 号元素哟!', {
            placements: ['top']
        });
    }
    else {
        textField.setErrorMessage(null); 
    }
});

The fourth line is a text area ht.ui.TextArea, used to display the element information of the query.

Memoirs of a programmer’s student days: 3D interactive visualization of the periodic table

 

The fifth row is a set of buttons used to submit query data and reset form information.

3D interface code analysis

Button group

Above is a ht.ui.HBoxLayout horizontal layout, 4 buttons are added to the hbox to perform 3D shape conversion.

Memoirs of a programmer’s student days: 3D interactive visualization of the periodic table

 

The button supports icons and text, and provides four states: normal, hover, active, and disabled. The button generates code:

createButton(text) {
    let button = new ht.ui.Button();
        button.setBorder(null);
        button.setHoverBorder(null);
        button.setActiveBorder(null);
        button.setBackground(new ht.ui.drawable.ColorDrawable('rgba(37,115,194,0.6)', 4)); // normal 背景
        button.setHoverBackground(new ht.ui.drawable.ColorDrawable('rgba(10,92,173,0.50)', 4)); // hover 背景
        button.setActiveBackground(new ht.ui.drawable.ColorDrawable('rgba(15,132,250,0.6)', 4)); // active 背景
        button.setText(text);
        button.setTextColor('rgb(0, 211, 255)');
        button.setHoverTextColor('rgb(0, 211, 255)');
        button.setActiveTextColor('rgb(0, 211, 255)');
    return button;
}

Use button.on('click', e => {// switch function}) to monitor the click event.

3D scene

Below is ht.graph3d.Graph3dView. Through the encapsulation of the underlying WebGL technology, like other components of HT, the graphics display is driven based on the HT unified DataModel data model, which greatly reduces the threshold for the development of 3D graphics technology. You are familiar with the HT data model. On the basis, general programmers only need 1 hour of study to get started with 3D graphics development.

The element is displayed as a patch in the 3D scene. 2D is the best vector map for the patch. The display style is also controlled by modifying the node properties.

node.s({
    'shape3d': 'billboard', // 设置节点类型为‘billboard’公告板
    'shape3d.image': 'symbols/元素2.json', // 设置面片贴图
    'shape3d.reverse.flip': true, // 设置反面是否显示正面内容
    'shape3d.image.cache': true, // 进行贴图缓存
    'shape3d.fixSizeOnScreen': false, // 设置是否固定保持屏幕大小,不随缩放而变化
    'select.brightness': 1 // 设置选中亮度为 1
});

Next, let's talk about several rotation changes. dm is the DataModel that is the bound data container, and datasMap is used to store the position information before and after the element changes, which is used when driving animation.

1.  Random scramble: set a set of spatial range values, generate (x, y, z) random values ​​in the range to set the node position.

let dm = this.dm,
    datasMap = {};
dm.each(data => {
    let x = Math.random() * 2000 - 1000; // 获取随机 x
    let y = Math.random() * 2000 - 1000; // 获取随机 y
    let z = Math.random() * 500 - 250; // 获取随机 z
    let position = data.getPosition3d(),
        px = position[0],
        py = position[1],
        pz = position[2];
    datasMap[data] = {
        x: x,
        y: y,
        z: z,
        px: px,
        py: py,
        pz: pz
    };
});

Memoirs of a programmer’s student days: 3D interactive visualization of the periodic table

 

2.  Spherical surround: generate point coordinates around a spherical helix.

let dm = this.dm,
    datas = dm.getDatas(),
    datasMap = {};
let r = 400,
    theta, phi;
for (let i = 0; i < 118; i++) { 
    let data = datas.get(i);
    theta = (i + 1) / 118 * 180; // 获取球系坐标
    phi = (i + 1) / 118 * 360 * 10; // 获取球系坐标
   // 球系坐标转换为 HT 三维坐标
    let z = r * Math.sin(theta * Math.PI / 180) * Math.cos(phi * Math.PI / 180),
        x = r * Math.sin(theta * Math.PI / 180) * Math.sin(phi * Math.PI / 180),
        y = r * Math.cos(theta * Math.PI / 180);
    let position = data.getPosition3d(),
    px = position[0],
    py = position[1],
    pz = position[2];
    datasMap[data] = {
        x: x,
        y: y,
        z: z,
        px: px,
        py: py,
        pz: pz
    };
}

Memoirs of a programmer’s student days: 3D interactive visualization of the periodic table

 

3.  Circular surround: set a circle radius, starting height, rotate at a fixed angle, and reduce the setting height of the node each time.

var dm = this.dm,
    datasMap = {},
    datas = dm.getDatas(),
    radius = 400,
    angle = 18,
    num = 360 / angle;
var y = 300, 
    count = 0;
for (var i = 0; i < 6; i++) {
    for (var j = 0; j < num; j++) {
        let data = datas.get(count),
            radian = Math.PI / 180 * j * angle;
        if (!data) break;
        count++;
        let x = radius * Math.cos(radian),
            z = radius * Math.sin(radian);
        let position = data.p3(),
            px = position[0],
            py = position[1],
            pz = position[2];
        datasMap[data] = {
            x: x,
            y: y,
            z: z,
            px: px,
            py: py,
            pz: pz
        };                
        y -= 6;
    }
}

Memoirs of a programmer’s student days: 3D interactive visualization of the periodic table

 

4.  Recovery: Calculate the xy value of the element node according to the number of rows and columns of the recorded element, and the z value is fixed.

var dm = this.dm,
    datasMap = {};
dm.each(data => {
    var index = data.a('index'),
        row = data.a('row'),
        col = data.a('col');
    var position = data.getPosition3d(),
        px = position[0],
        py = position[1],
        pz = position[2];
    datasMap[data] = {
        index: index,
        row: row,
        col: col,
        px: px,
        py: py,
        pz: pz
    };
});

Memoirs of a programmer’s student days: 3D interactive visualization of the periodic table

 

5.  Animation when element switching states: Learn more about the animation of the introductory manual https://www.hightopo.com/guide/guide/core/beginners/ht-beginners-guide.html#ref_animation

ht.Default.startAnim({
    duration: 1500,
    easing: function(t) { 
        return t * t;
    },
    action: function(v, t) {
        dm.each(data => {
            let info = datasMap[data],
                x = info.x,
                y = info.y,
                z = info.z,
                px = info.px,
                py = info.py,
                pz = info.pz;
            data.p3(px + v * (x - px), py + v * (y - py), pz + v * (z - pz)); // 移动元素位置
            data.lookAt([0, y, 0], 'back'); // 调整元素朝向
        });
    }
});

Guess you like

Origin blog.csdn.net/iotopo/article/details/108100641