preface

The “industrial Internet” promoted by GENERAL Electric (GE), IBM, Intel and other companies is undergoing the evolution of “product – data analysis platform – application – ecology”. This is driven by the Predix data analytics platform’s ability to integrate industrial Internet applications. Like iOS or Android for industrial data, Predix will allow engineers to build models and applications on their own, connecting tens of thousands of sensors in front of them with more than 50 million new databases added every day behind them.

In practical applications, China Eastern Airlines collected high-pressure turbine blade warranty data from more than 500 CFM56 engines using industrial Internet applications on Predix, and established a blade damage analysis and prediction model by combining remote diagnostic records with third-party data. Once upon a time, airlines regularly forced planes to take “sick leave” by sticking tiny cameras into their engines. Engine performance can now be predicted based on results from the data analysis platform, customizing scientific repeat check intervals and improving operational efficiency. Remove the aviation sector, factory warehouse supervision is also very need the intervention of the Internet, not only can real-time monitoring the current data warehouse and information, also can reduce the number of warehouse supervisor, more able to predict the warehouse fault information and inform the staff in advance to take corresponding measures, can effectively avoid the damage caused by factory operations suspended.

Code generation

This example is deployed in es6 modular fashion. Open index.html and go to lib/index.js. The source code is in the SRC folder

Load modules with export interface in other modules at the top:

import sidebar from './sidebar.js';
import header from './header.js';
import BorderLayout from './common/BorderLayout.js';
import shelfPane from './common/shelfPane.js';
import chartPane from './common/chartPane.js';
import graph3dView from './3d/index';
Copy the code

Scene layout

We split each part of the page into a separate JS file, the js export part loaded above, the root container BorderLayout (the outermost div of the whole), and the whole part of the image is based on the BorderLayout.

The outermost container, BorderLayout, is a custom class in borderLayout.js under SRC/View /common, Ht.default. def(className, superClass, methods) is the function of the user-defined class encapsulated in HT, where className is the name of the user-defined class and superClass is the parent class to be inherited. The methods for the method and the variable declarations, to use this method to outside the function variables, through the functionName.. SuperClass constructor. Call inheritance (this) method. BorderLayout custom class inherits the ht. The UI. The drawable. BorderLayout component layout, this layout editor’s own space is divided into the up, down, left, right, middle five regions, each region can be placed a child component. For normal interaction, rewrite the getSplitterAt function to change the width of splitterRect to 10, and rewrite the layoutSplitterCanvas method to resize the left splitterCanvas to block the child components:

let BorderLayout = function() {
    BorderLayout.superClass.constructor.call(this);
    this.setContinuous(true); this.setSplitterSize(0); }; Ht.default. def(BorderLayout, HT.ui.BorderLayout, {// Custom classes /** * splitter width is 0, for normal interaction, Override this function to change the width of splitterRect to 10 * @override */ getSplitterAt:functionVar leftRect = this._leftSplitterRect, lp;if (leftRect) {
            leftRect = ht.Default.clone(leftRect);
            leftRect.width = 10;
            leftRect.x -= 5;
            if (event instanceof Event)
                lp = this.lp(event);
            else
                lp = event;
            if (ht.Default.containsPoint(leftRect, lp)) return 'left';
        }
        returnBorderLayout.superClass.getSplitterAt.call(this, event); }, /** * resize the left splitterCanvas to block the child component * @override */ layoutSplitterCanvas:function(canvas, x, y, width, height, region) {
        if (region === 'left') {
            canvas.style.pointerEvents = ' ';
            canvas.style.display = 'block';
            ht.Default.setCanvas(canvas, 10, height);
            canvas.style.left = this.getContentLeft() + this.tx() + x - 5 + 'px';
            canvas.style.top = this.getContentTop() + this.ty() + y + 'px';
        }
        else{ BorderLayout.superClass.layoutSplitterCanvas.call(this, canvas, x, y, width, height, region); }}});export default BorderLayout;
Copy the code

On the left side of the bar

Sidebar on the left side is divided into 8 parts: top logo, cargo position statistics form, progress bar, dividing line, cargo form, chart, management group, problem feedback button, etc.

Check out the sidebar. Js file under SRC /view, The same js files loaded under SRC/view/common TreeHoverBackgroundDrawable. Js and ProgressBarSelectBarDrawable in js TreeHoverBackgroundDrawable and ProgressBarSelectBarDrawable variables, and the sidebar under SRC/controller. The controller variables in js:

import TreeHoverBackgroundDrawable from './common/TreeHoverBackgroundDrawable.js';
import ProgressBarSelectBarDrawable from './common/ProgressBarSelectBarDrawable.js';
import controller from '.. /controller/sidebar.js';
Copy the code

HT wraps a function called HT.ui. VBoxLayout to place all the components in the same vertical column. We can place all the left columns in this component so that all the components are in a vertical column:

letvBoxLayout = new ht.ui.VBoxLayout(); // This arranger places child components in the same vertical column; vBoxLayout.setBackground('#17191a'); 
Copy the code

The top logo is implemented by adding an icon to the Label Label and adding the topLabel to the vertical column vBoxLayout:

lettopLabel = new ht.ui.Label(); // Toplabel.settext ('Demo-logo'); // Set the text content toplabel.seticon ('imgs/logo.json'); Toplabel.seticonwidth (41); toplabel.setiConWidth (41); topLabel.setIconHeight(37); topLabel.setTextFont('18px arial, sans-serif');
topLabel.setTextColor('#fff'); topLabel.setPreferredSize(1, 64); // Toplabel.setBackground (toplabel.setBackground ('RGB (49,98,232)'); Vboxlayout. addView(topLabel, {// Add child components to the container width:'match_parent'// Fill the parent container});Copy the code

For the “cargo position statistics table”, we use the HT-encapsulated TreeTableView component to present the data element attributes and parent-child relationships in the DataModel as a combination of tree and table, and add the “tree table” to the vertical column vBoxLayout:

letshelfTreeTable = new ht.ui.TreeTableView(); / table/tree components, appears in the combination of tree and tabular data element attribute and parent-child relationships in the DataModel shelfTreeTable. SetHoverBackgroundDrawable (new TreeHoverBackgroundDrawable ('#1ceddf', 2)); / / set the hover state downward selected background Drawable object shelfTreeTable. SetSelectBackgroundDrawable (new TreeHoverBackgroundDrawable ('#1ceddf', 2)); / line/set selected background Drawable object parameters for "background shelfTreeTable. SetBackground (null); shelfTreeTable.setIndent(20); / / setting different levels of indentation value shelfTreeTable setColumnLineVisible (false); . / / whether the column lines visible shelfTreeTable setRowLineVisible (false);
shelfTreeTable.setExpandIcon('imgs/expand.json'); / / Settings icon, can be a color or image shelfTreeTable. SetCollapseIcon ('imgs/collapse.json'); / / Settings icon in the merger, can be a color or picture etc shelfTreeTable. The setPreferredSizeRowCountLimit (); Shelftreetable.setid (); // Set the number of rows to limit when calculating the preferredSize'shelfTreeTable');
vBoxLayout.addView(shelfTreeTable, {
    width: 'match_parent',
    height: 'wrap_content',// the component's preferred height marginTop: 24, marginLeft: 4, marginRight: 4});Copy the code

When we set the “line” selected background introduced into a TreeHoverBackgroundDrawable object, the object is in the SRC \ view \ TreeHoverBackgroundDrawable under common defined in js file, Ht.default. def(className, superClass, methods) is the function of the user-defined class encapsulated in HT, where className is the name of the user-defined class and superClass is the parent class to be inherited. The methods for the method and the variable declarations, to use this method to outside the function variables, through the functionName.. SuperClass constructor. Call inheritance (this) method. TreeHoverBackgroundDrawable custom class inherits the ht. The UI. The drawable. The drawable components used to draw the background, ICONS, etc., only rewrite the draw and getSerializableProperties two methods, We redraw the shelfTreeTable line in the draw method to select the background color, and reload the getSerializableProperties serialization component function, And TreeHoverBackgroundDrawable into the parameter as the map of newly added attributes:

let TreeHoverBackgroundDrawable = function(color, width) {
    TreeHoverBackgroundDrawable.superClass.constructor.call(this);
    this.setColor(color);
    this.setWidth(width);
};
ht.Default.def(TreeHoverBackgroundDrawable, ht.ui.drawable.Drawable, {
    ms_ac: ['color'.'width'],
    draw: function(x, y, width, height, data, view, dom) {
        var self = this,
            g = view.getRootContext(dom),
            color = self.getColor();
       
        g.beginPath();
        g.fillStyle = color;
        g.rect(x, y, self.getWidth(), height);
        g.fill();
    },
    getSerializableProperties: function() {
        var parentProperties = TreeHoverBackgroundDrawable.superClass.getSerializableProperties.call(this);
        returnaddMethod(parentProperties, { color: 1, width: 1 }); }});Copy the code

Remember to export TreeHoverBackgroundDrawable:

export default TreeHoverBackgroundDrawable;
Copy the code

HT also includes a very useful hT.ui.Progressbar component that allows you to draw progress bars directly:

let progressBar = new ht.ui.ProgressBar();
progressBar.setId('progressBar');
progressBar.setBackground('#3b2a00'); // Set the component's background, which can be a color or an image, etc. Progressbar.setbar ('rgba (0,0,0,0)'); // Set progressbar.setPADDING (5); // Set progressbar.setpadding (5); progressBar.setSelectBarDrawable(new ProgressBarSelectBarDrawable('#c58348'.'#ffa866')); Progressbar.setvalue (40); // Set the Drawable object for progressbar.setValue (40); / / set the current progress value progressBar. SetBorderRadius (0); vBoxLayout.addView(progressBar, { marginTop: 24, width:'match_parent',
    height: 28,
    marginBottom: 24,
    marginLeft: 14,
    marginRight: 14
});
Copy the code

We set the “outlook” when introduced into a ProgressBarSelectBarDrawable object, the object under the SRC \ views \ common ProgressBarSelectBarDrawable. Js defined. Specific definition method above TreeHoverBackgroundDrawable function object, go here.

The easiest way to create a divider is to set the height of a rectangle to 1, using the hT.ui.view () component:

letseparator = new ht.ui.View(); // The base class for all view components, from which all visual components must inherit separate.setBackground ('# 666');
vBoxLayout.addView(separator, {
    width: 'match_parent',
    height: 1,
    marginLeft: 14, 
    marginRight: 14,
    marginBottom: 24
});
Copy the code

The operation of the cargo table is almost the same as that of the cargo position statistics table, which will not be described here.

We can also easily manipulate a JSON chart file as a picture passed to the chart component container as the background:

let chartView = new ht.ui.View();
chartView.setBackground('imgs/chart.json');
vBoxLayout.addView(chartView, {
    width: 173,
    height: 179,
    align: 'center',
    marginBottom: 10
});
Copy the code

The management group and the top logo are defined in a similar way and will not be described here.

For the feedback Button, we made this part with hT.ui. Button component wrapped in HT, and added this part into the vertical column vBoxLayout:

letfeedbackButton = new ht.ui.Button(); // Feedbackbutton. setId('feedbackButton');
feedbackButton.setText('Question feedback: [email protected]');
feedbackButton.setIcon('imgs/em.json');
feedbackButton.setTextColor('#fff'); feedbackButton.setHoverTextColor(shelfTreeTable.getHoverLabelColor()); / / set the text color feedbackButton hover condition. SetActiveTextColor (feedbackButton. GetHoverTextColor ()); / / set the active state text color feedbackButton setIconWidth (16); feedbackButton.setIconHeight(16); feedbackButton.setIconTextGap(10); feedbackButton.setAlign('left');
feedbackButton.setBackground(null);
feedbackButton.setHoverBackground(null);
feedbackButton.setActiveBackground(null);
vBoxLayout.addView(feedbackButton, {
    width: 'match_parent',
    marginTop: 5,
    marginBottom: 10,
    marginLeft: 20
});
Copy the code

interaction

The view part is done. In modular development, controller is the interactive part, shelfTreeTable inventory table, cargoTreeTable inventory table, feedbackButton problem feedbackButton, The interactions for all four sections of the progressBar progressBar are defined in sidebar.js under SRC /controller. FindViewById (id, recursive) is used to find subcomponents based on their ID, recursive indicating whether or not they are recursively searched.

ShelfTreeTable cargo table data binding transfer mode is similar to cargoTreeTable cargo table, here we only parse the data binding of shelfTreeTable cargo table. The shelfTreeTable has three columns, and the only different parts of the shelfTreeTable are the “used” and “remaining” parts, so we just need to bind these two parts to the data.

letcolumn = new ht.ui.Column(); // Column data, used to define the column information of the table component column.setname ('used'); // Set the data element name column.setAccesstype ('attr'); // where name is used, getAttr('used') andsetAttr('used', 98)set/getAttr short for a column. SetWidth (65); column.setAlign('center');
columnModel.add(column);

column = new ht.ui.Column();
column.setName('remain');
column.setAccessType('attr');
column.setWidth(65);
column.setAlign('center');
columnModel.add(column);
Copy the code

Then iterate over the JSON file and bind the corresponding Used, Remain, and labelColors in the JSON file with set/getAttr or short A:

for(var i = 0; i < json.length; i++) { var row = json[i]; Var data = new ht.data (); data.setIcon(row.icon); // Pass the icon in json data.setName(row.name); data.a('used', row.used);
    data.a('remain', row.remain);
    data.a('labelColors', row.colors); data.setIcon(row.icon); treeTable.dm().add(data); Var children = row.children; var children = row.children;if (children) {
        for (var j = 0; j < children.length; j++) {
            var child = children[j];
            var childData = new ht.Data();
            childData.setName(child.name);
            childData.setIcon(child.icon);
            childData.a('used', child.used);
            childData.a('remain', child.remain);
            childData.a('labelColors', child.colors); childData.setParent(data); treeTable.dm().add(childData); }}}Copy the code

Finally call this function in the Controller function object:

initTreeTableDatas(shelfTreeTable, json); / / json for.. Imported/model/shelf. JsonCopy the code

The progressBar progressBar is dynamically changed by setting a timer to change the value of the progressBar:

setInterval(() => {
    if(progressBar.getValue() >= 100) { progressBar.setValue(0); } progressBar.setValue(progressBar.getValue() + 1); }, 50); FeedbackButton problem feedback button, by increasing the View event listener to listen on button click event: feedbackButton. AddViewListener (e = > {if (e.kind === 'click') {/ / HT custom event attributes, specific view window. The http://hightopo.com/guide/guide/core/beginners/ht-beginners-guide.html location. The href ="mailto:[email protected]"; }});Copy the code

The container splitLayout on the right

Ht.ui.SplitLayout:

letsplitLayout = new ht.ui.SplitLayout(); / / this layout, its space is divided into upper and lower two area or left and right two regions, each region can be placed a child component splitLayout. SetSplitterVisible (false);
splitLayout.setPositionType('absoluteFirst');
splitLayout.setOrientation('v');
Copy the code

Right header header

Here we do not have the “search box” searchField data binding, and search capabilities, this is just a sample, not involved in the business part:

letsearchField = new ht.ui.TextField(); // Searchfield. setBorder(new ht.ui.border.LineBorder(1,'#d8d8d8')); / / in the component of the canvas. Draw a straight line border searchField setBorderRadius (12); searchField.setBackground(null); searchField.setIcon('imgs/search.json');
searchField.setIconPosition('left');
searchField.setPadding([2, 16, 2, 16]);
searchField.setColor('rgb(138, 138, 138)');
searchField.setPlaceholder('Find everything... ');
searchField.getView().className = 'search';
header.addView(searchField, {
    width: 180,
    marginLeft: 20,
    vAlign: 'middle'
});
Copy the code

The main title of titleLabel is relatively simple, similar to temperature, humidity and air pressure. I will just explain the definition of the main title titleLabel:

lettitleLabel = new ht.ui.Label(); // Titlelabel.setid ('title');
titleLabel.setIcon('imgs/expand.json');
titleLabel.setTextColor('rgb(138, 138, 138)');
titleLabel.setText('Hangzhou Warehouse');
titleLabel.setHTextPosition('left'); // Sets the horizontal position of the text relative to the icon. The default is'right'titleLabel.setIconTextGap(10); / / set spacing between icon and text titleLabel setBorder (new ht. UI. Border. IndividualLineBorder (0, 0, 3, 0,'#3162e8')// Draw a straight border on the canvas of the component; Unlike LineBorder, this border can be drawn separately in one or more directions titlelabel.settextFont ('16px arial');

header.addView(titleLabel, {
    height: 'match_parent',
    width: 'wrap_content',
    align: 'center'
});
Copy the code

Then the interaction part is made in the header. Js under SRC /controller by right clicking the menu bar and clicking the titleLabel position to appear the drop-down menu. The interaction of the event is controlled by controlling the mouse click event:

let title, contextMenu;
export default function controller (view) {
    title = view.findViewById('title'); contextMenu = new ht.ui.ContextMenu(); / / right-click menu component contextMenu. SetLabelColor ('rgb(138, 138, 138)');
    contextMenu.setHoverRowBackground('#3664e4');
    contextMenu.setItems([
        {
            label: 'Beijing Warehouse'
        },
        {
            label: 'Shanghai Warehouse'
        },
        {
            label: 'Xiamen Warehouse'}]); contextMenu.addViewListener((e) => {if (e.kind === 'action') {// HT custom event type title.settext (e.tem.label); }}); title.getView().addEventListener('mousedown', e => {
        if(contextmenu.isindom ()) {contextmenu.hide (); / / hide menu document. RemoveEventListener ('mousedown', handleWindowClick); // Remove the mousedown listener}elseVar items = contextmenu.getitems ();for (var i = 0; i < items.length; i++) {
                items[i].width = title.getWidth();
            }

            letWindowInfo = ht. Default. GetWindowInfo (), / / get the current window left | top | width | titleRect = height parameter information title.getView().getBoundingClientRect(); contextMenu.show(windowInfo.left + titleRect.left, windowInfo.top + titleRect.top + titleRect.height); document.addEventListener('mousedown', handleWindowClick); }}); }function handleWindowClick(e) {
    if(! contextMenu.getView().contains(e.target) && ! Title.getview ().contains(e.target)) {// Check whether the element is in the array contextmenu.hide (); document.removeEventListener('mousedown', handleWindowClick); }}Copy the code

The bottom right side relative to the bottom right div contains a graph3dView that displays 3D in the center, a shelfPane that appears when you double click on a container or cargo, and a chart chartPane that appears in the bottom right. Add these three sections to the RelativeLayout layout container:

letrelativeLayout = new ht.ui.RelativeLayout(); // Create a relativelayout.setid ('contentRelative');
relativeLayout.setBackground('# 060811');

var htView = new ht.ui.HTView(graph3dView);
htView.setId('contentHTView'); Relativelayout.addview (htView, {// Add 3d components to the relativelayout.width:'match_parent',
    height: 'match_parent'}); Relativelayout.addview (shelfPane, {// Add the details of the shelfPane component to the relativeLayout layout. Width: 220, height:'wrap_content',
    align: 'right', marginRight: 30, marginTop: 30 }); Relativelayout. addView(chartPane, {// Add the chartPane component to the relativeLayout. Width: 220, height: 200, align:'right',
    vAlign: 'bottom',
    marginRight: 30,
    marginBottom: 30
})
Copy the code

Then add the right relativeLayout and the right header to the bottom right container splitLayout:

let splitLayout = new ht.ui.SplitLayout();
splitLayout.setSplitterVisible(false);
splitLayout.setPositionType('absoluteFirst');
splitLayout.setOrientation('v');
splitLayout.addView(header, {
    region: 'first'// Specify the region where the component resides. The options are:'first'|'second'
});
splitLayout.addView(relativeLayout, {
    region: 'second'
});
Copy the code

Add the sidebar of the left part and all of the right part (i.e., splitLayout) to the entire bottom container, borderLayout, and add the bottom container to the HTML body:

let borderLayout = new BorderLayout();
borderLayout.setLeftWidth(250);
borderLayout.addView(sidebar, {
    region: 'left',// Specify the region where the component resides. The options are:'top'|'right'|'bottom'|'left'|'center'
    width: 'match_parent'// The component's preferred width}); borderLayout.addView(splitLayout, { region:'center'}); borderLayout.addToDOM(); // Add the borderLayout to the bodyCopy the code

Let’s talk about the graph3dView, the 3D part contained within the relative layout, the shelfPane, which appears when you double click on a container or cargo, and the chartPane, which appears in the lower right corner of the diagram.

The 3 d scene

The external interface to get the graph3dView from the index.js folder in SRC \ View \3d is called from the index.js folder in SRC/View:

import graph3dView from './3d/index';
Copy the code

As you can see from this 3D scene, we need “floors”, “walls”, “shelves”, “forklifts”, “goods” and 3d scenes.

In index.js under the 3D folder, we import all the interfaces we need from the folder:

SceneWidth, sceneHeight, sceneTall, toShelfList, randomCargoType} from'./G.js'; Import {stockinout,// Initiate initialization of inoutShelf} from'./interfaces';

import { Shelf } from './shelf'; // shelf import {Floor} from'./floor'; // floor import {Wall} from'./wall'; Import {Car} from'./car'; // forklift import {g3D} from'./g3d'; // 3d scene import {getCargoById} from'./cargo'; G3d. mi((e) => {// addInteractorListener const kind = e.type;if (kind === 'doubleClickData') {// Double-click the icon eventletdata = e.data; // Event-related data elementsif(data instanceof Shelf) {// If data.settransparent (false);

      eventbus.fire({ type: 'cargoBlur'}); // Call all listener functions in sequence}else {
      data = data.a('cargo');
      if(! data)return;
      data.transparent = false;

      eventbus.fire({ type: 'cargoFocus', data: data });
    }

    for (leti = shelfList.length - 1; i >= 0; Const shelf = shelfList[I]; shelf.setTransparent(true, data);
    }
    return;
  }
  if (kind === 'doubleClickBackground') {// Double-click the background eventfor (leti = shelfList.length - 1; i >= 0; Const shelf = shelfList[I]; shelf.setTransparent(false);
    }

    eventbus.fire({ type: 'cargoBlur' });
    return; }});Copy the code

We define some base data in g.js that will be called repeatedly in any other referenced JS, so let’s parse this file first:

const sceneWidth = 1200; // Width const sceneHeight = 800; // Scene height const sceneTall = 410; // Depth of the scene const globalOpacity = 0.3; Const cargoTypes = {const cargoTypes = {const cargoTypes = {const cargoTypes ='cask': {/ / barrel'name': 'bucket'
  },
  'carton': {/ / carton'name': 'carton'
  },
  'woodenBox1': {// Wooden box 1'name': 'woodenBox1'
  },
  'woodenBox2'{// Wooden case 2'name': 'woodenBox2'}};Copy the code

There are three functions, namely “obJ decomposition of shelves”, “loading model” and “type of randomly allocated goods” :

functionToShelfList (list) {// Split shelf obj, const obj = {}; View /3d/interface. Js const STRS = o.cubegeoid.split ()The '-');

    let rs = obj[o.rackId];
    if(! rs) { rs = obj[o.rackId] = []; } const ri = parseInt(strs[2].substr(1)) - 1;let ps = rs[ri];
    if(! ps) { ps = rs[ri] = []; }let type = 'cask';
    if (o.inventoryType === 'Import') {
      while((type = randomCargoType()) === 'cask') {}
    }

    const pi = parseInt(strs[3].substr(1)) - 1;
    ps[pi] = {
      id: o.cubeGeoId,
      type: type
    };
  });

  return obj;
}

functionLoadObj (shape3d, fileName, cbFunc) {// Load model const path ='./objs/' + fileName;
  ht.Default.loadObj(path + '.obj', path + '.mtl', {
    shape3d: shape3d,
    center: true,
    cube: true,
    finishFunc: cbFunc
  });
}

function randomCargoTypeConst keys = object.keys (cargoTypes); const keys = object.keys (cargoTypes); const i = Math.floor(Math.random() * keys.length);return keys[i];
}
Copy the code

There are also the indispensable “goods” and “shelves” as well as “forklifts” in this 3D scene. The three are defined in a similar way, and only “shelves” is explained here. We directly import the js file of the bottom “tray” into the JS file of the “goods” and treat them as a whole:

import { Pallet } from './pallet';
import {
  cargoTypes,
  loadObj,
  globalOpacity
} from './G';
Copy the code

In the SRC \view\3d\cargo. Js file, we define a “cargo” class. This class declares a lot of methods. LoadObj: loadObj: loadObj: loadObj: loadObj: loadObj: loadObj: loadObj: loadObj: loadObj: loadObj: loadObj: loadObj: loadObj

for (let type inCargoTypes) {// Iterate over the array of cargoTypes, const cargo defined in g.js = cargoTypes[type];
  loadObj(type, cargo. Name, (map, array, s3) => {// loadObj(shape3d, fileName, cbFunc) For parameters in cbFunc, see cargo. // Set cargo's s3 to the original size updateCargoSize(); }); }function updateCargoSize() {
  let c, obj;
  for (let i = cargoList.length - 1; i >= 0; i--) {
    c = cargoList[i];

    obj = cargoTypes[c.type];
    if(! obj.s3)continue; c.boxS3 = obj.s3; }}Copy the code

The main method is hT.default. startAnim function (HT for Web Animation Manual) encapsulated by HT. The outgoing animation is similar to the incoming animation, which will not be described here:

/ / into the goodsin() {
    if(anim) {// If there is a value, stop the animation im.stop(true); } this.x = this.basicX + moveDistance; this.opacity = 1; Anim = ht.default. startAnim({duration: 1500, finishFunc: () => {// Call this function after the animation ends and set anim to null to stop animation anim = null; }, action: (v, t) => { this.x = this.basicX + (1 - v) * moveDistance; // Change the x coordinate to look like moving forward}}); }Copy the code

Ht. Node and HT. Shape are also very simple. We can simply inherit the hT. Node and HT. Shape properties.

Constructor (points, segments, tall, thickness, elevation) {super(); this.setPoints(points); // set "point" this.setSegments(segments); // Set the connection mode between dots this.settall (tall); // Controls the length of the Node element on the y axis this.setthickness (thickness); // Set the "thickness" this.setelevation (elevation); / / control Node figure yuan central location where the 3 d coordinate system the y position of the enclosing s ({'all.transparent': true// Six transparent sides'all.opacity': 0.3,// Transparency is 0.3'all.reverse.flip': true// The reverse side of the six sides displays the positive content'bottom.visible': false// The bottom is not visible}); }}Copy the code

The four classes of Floor, Wall, shelf and CAR are ready. We just need to create a new object in SRC \view\3d\index.js and add it to the dataModel. Here we only show the initialization code of car “forklift” :

// init Car
const car = new Car();
car.addToDataModel(dm);
Copy the code

As for “goods”, we use the timer to call in and out methods on this JS. Here is a simulated database interfaces.js file, if you need to look at it, we call it as data only.

// Use the inbound/outbound interfacesetInterval(() => { const obj = stockinout(); For the ins / /let type = 'cask';
  if (obj.inventoryType === 'Import') {
    while((type = randomCargoType()) === 'cask') {}// If the "cargo" type is "barrel"} car.cargoType =type;
  if (obj.inOutStatus === 'I')// If the value is "I", go to car.in();else// otherwise "o", car.out(); }, 30000);Copy the code

shelves

The external interface to get graph3dView from shelfpane.js in SRC \ View \common is called by index.js in SRC/View:

import shelfPane from './common/shelfPane.js';
Copy the code

ShelfPane is based on the Pane class. Introduce this class and event dispatcher in the shelfPane.js file:

import Pane from './Pane.js';
import eventbus from '.. /.. /controller/eventbus';
Copy the code

The Pane class inherits from the HT.ui. TabLayout class wrapped in HT and makes some specific property Settings:

class Pane extends ht.ui.TabLayout {
    constructor() {
        super();

        this.setBorder(new ht.ui.border.LineBorder(1, 'RGB (150150150).)); / / set the component frame enclosing setTabHeaderBackground (null); / / set the tag line background, can be a color or pictures, etc. This setHoverTabBackground (null); / / set the Hover state under the label of the background, can be a color or pictures, etc. This setActiveTabBackground (null); SetTitleColor () setTitleColor() setTitleColor()'RGB (184184184).); This. setActiveTitleColor() setActiveTitleColor()'RGB (255255255).); / / set the Active state of the color of the label text enclosing setTabHeaderLineSize (0); // Set the label line split width this.setmovable (false); // Sets whether the label can be dragged to adjust the positiontrue
        this.setTabHeaderBackground('#1c258c'); This. setTabGap(0); // Set the background of the label line, which can be a color or image. GetTabWidth (child) {const children = this.getChildren(), size = children.size();if (size === 0) {
            returnthis.getContentWidth(); // Get the content width, that is, the component width minus the border width and left and right margin width}else {
            returnthis.getContentWidth() / size; }} drawTab(g, child, x, y, w, h) const children = this.getChildren(), size = children.size(), Color = this. GetCurrentTitleColor (child), / / child components according to the parameters of state (normal, hover, active, move). Font = this.gettitleFont (child),// getTitleFont = this.getTitle(child); // Gets the label text of the specified child componentif (size === 1) {
            ht.Default.drawText(g, title, font, color, x, y, w, h, 'left'); // Draw text}else {
            ht.Default.drawText(g, title, font, color, x, y, w, h, 'center');
        }

        if(children.indexOf(child) < size - 1) { g.beginPath(); // start drawing g.point (x + w-1, y + 4, 1, h-8); g.fillStyle ='RGB (150150150).; g.fill(); }}show() {
        this.setVisible(true); // Set component visible}hide() {
        this.setVisible(false); }}Copy the code

The “information” list in our example is a table component. HT defines a table using hT.uI. TableLayout and then adds rows to the table using HT.ui. TableRow. In this example, “Remarks”, “Number”, “source”, “In”, “to”, and “out” are all text boxes. Take “Remarks” as an example:

lettableLayout = new ht.ui.TableLayout(); / / this layout to follow its own space ranks are divided into row. * the column cell tableLayout setColumnPreferredWidth (0, 45); / / set the column width tableLayout preferred. SetColumnWeight (0, 0). // Set the column width weight; If the layout of the total width is greater than the sum of the preferred width of all columns, then the rest of the width according to the weight distribution tableLayout. SetColumnPreferredWidth (1, 150); tableLayout.setPadding(8); // Set the inner margin of the component. If the parameter is a number, it means that the four sides use the same inner margin; Var tableRow1 = new ht.ui.tablerow (); var tableRow1 = new ht.ui.tablerow (); // A row of subcomponents in the table; var label = new ht.ui.Label(); // Label component label.settext ('note'); // Set the text content label.setalign ('left'); // Sets the overall alignment of text and ICONS in the horizontal direction of the button. Default is'center'
label.setTextColor('RGB (255255255).); Var textField = new ht.ui.textField (); / / text box component textField. SetFormDataName ('remark'); // Set the name of the component in the form textField.setBackground(null); // Set the background of the component. This value will be converted to the Drawable object textField. SetBorderRadius (0); // Set CSS border rounded textField.setColor('RGB (138138138).); // Set the text color to textField.setplaceholder ('no'); / / set the input prompt textField. SetBorder (new ht. UI. Border. IndividualLineBorder (0, 0, 1, 0,'RGB (138138138).)); // Set the component's border tablerow1.addView (label); // Add a child component tablerow1.addView (textField); tableLayout.addView(tableRow1); // Add the child component to the containerCopy the code

The ht.ui.ComboBox component encapsulated in HT is similar to hT.ui. TextField, but the specific operation is different. HT is easier to use and easier to use. Here we use “model” to parse. When setting up “pull down data” we use data binding in HT:

Var tableRow4 = new ht.ui.tablerow (); label = new ht.ui.Label(); label.setText('model');
label.setAlign('left');
label.setTextColor('RGB (255255255).);

var comboBox = new ht.ui.ComboBox();
comboBox.setFormDataName('model');
comboBox.setBackground(null);
comboBox.setColor('rgb(232,143,49)'); Combobox.setdatas ([// sets the drop down data array {label:'the cartons', value: 'carton' },
  { label: 'the cases 1', value: 'woodenBox1' },
  { label: 'the cases 2', value: 'woodenBox2' },
  { label: 'barrel', value: 'cask'}]); comboBox.setIcon('imgs/combobox_icon.json');
comboBox.setHoverIcon('imgs/combobox_icon_hover.json');
comboBox.setActiveIcon('imgs/combobox_icon_hover.json'); comboBox.setBorderRadius(0); / / set the CSS border round comboBox. SetBorder (new ht. UI. Border. IndividualLineBorder (0, 0, 1, 0,'RGB (138138138).));

tableRow4.addView(label);
tableRow4.addView(comboBox);

tableLayout.addView(tableRow4);
Copy the code

ColorPicker component, which inherits from ht.ui.bobox and uses HT.ui.colorDropdown as a drop-down template, similar to the previous drop-down list, except that the drop-down template has been changed:

Var tableRow9 = new ht.ui.tablerow (); label = new ht.ui.Label(); label.setText('stain');
label.setAlign('left');
label.setTextColor('RGB (255255255).); var comboBox = new ht.ui.ColorPicker(); // Combobobox. SetFormDataName ('blend'); // Set the component's name in the form combobox.getView ().className ='content_colorpicker'; comboBox.setBackground(null); comboBox.setPreviewBackground(null); // Set the preview background; The value can be a color or image, such as combobobox.getinput ().style.visibility ='visible'; ComboBox. SetReadOnly (comboBox.true); // set combobox.setcolor ('rgba (0,0,0,0)');
comboBox.setPlaceholder('Change the color of the container');
comboBox.setIcon('imgs/combobox_icon.json');
comboBox.setHoverIcon('imgs/combobox_icon_hover.json');
comboBox.setActiveIcon('imgs/combobox_icon_hover.json');
comboBox.setBorderRadius(0);
comboBox.setBorder(new ht.ui.border.IndividualLineBorder(0, 0, 1, 0, 'RGB (138138138).));
comboBox.setInstant(true); // Set instant mode; In this mode, each character value is enteredCopy the code

Property change events are dispatched immediately, otherwise only when you lose focus or hit Enter

tableRow9.addView(label);
tableRow9.addView(comboBox);

tableLayout.addView(tableRow9);
Copy the code

Finally, the addChangeListener event listener function of hT.ui. Form component is used to monitor the overall change event of JSON and the change event of a single piece of data in JSON. The two events are explained as follows:

Specific monitoring methods are as follows:

form.addChangeListener((e) => {
  const cargo = form.__cargo__;
  if (e.kind === 'formDataValueChange') {// JSON const name = e.name;let value = e.newValue;

    if (name === 'blend') {
      if (value && value.startsWith('rgba')) {
        const li = value.lastIndexOf(', ');
        value = 'rgb' + value.substring(value.indexOf('('), li) + ') '; } } cargo.setValue(name, value); }});Copy the code

The HT. Notifier event dispatcher (HT. Notifier) enables components in different areas on the INTERFACE to interact with each other through event dispatcher and performs different actions according to different event types.

Eventbus. add((e) => {// add listener eventbus; Components in different areas of the interface interact with each other through event distributionif (e.type === 'cargoFocus') { shelfPane.show(); const cargo = e.data; form.__cargo__ = cargo; const json = form.getJSON(); // Get JSON data assembled from the names and values of the form componentsfor (let k in json) {
      form.setItem(k, cargo.getValue(k));
    }
    return;
  }
  if (e.type === 'cargoBlur') {
    shelfPane.hide();
    return; }});Copy the code

The chart

The external interface to get graph3dView from chartpane.js in SRC \ View \common is called by index.js in SRC/View:

import chartPane from './common/chartPane.js';
Copy the code

ChartPane and shelfPane are similar in that they are objects of the Pane class and have similar properties, except content. Since this is just a Demo, we haven’t done much with the chart plugin, so we use pictures instead of dynamic charts, but it’s easy to do even if you want to, there are more interesting examples on the HT website!

Getting back to business, the chartPane chart panel is easy to implement by adding background images of internal child components to the chartPane Chart panel:

import Pane from './Pane.js';

var chartPane = new Pane();

var view1 = new ht.ui.View();
view1.setBackgroundDrawable(new ht.ui.drawable.ImageDrawable('imgs/chart.png'.'fill')); // Set the component's background Drawable object; Var view2 = new ht.ui.view (); view2.setBackgroundDrawable(new ht.ui.drawable.ImageDrawable('imgs/chart.png'.'fill'));

chartPane.getView().style.background = 'rgba (18,28,64,0.60)'; // Set the background color chartpane.addView (view1, {// Add the child component to the container title:'Other Charts'
});

chartPane.addView(view2, {
    title: 'Inventory load'}); chartPane.setActiveView(view2); // Sets the selected child componentCopy the code

After the analysis of the whole example, interested partners can go to the OFFICIAL website of HT (http://www.hightopo.com/) for self-study and reference. Have a good taste and you will find a bigger world.

http://www.hightopo.com/demo/large-screen/index.html

conclusion

China’s manufacturing industry, which has always been the world’s “manufacturing factory”, is facing unprecedented challenges. On the one hand, After the trade war, China will import more and open up to the world. More Teslaas will enter China, posing threats to the local manufacturing industry. On the other hand, China’s manufacturing industry has been facing the problem of overcapacity and foreign trade needs to be solved. Seizing the trend of upgrading domestic consumption, it is an inevitable choice to take the road of export to domestic sales. To take this road well, we also need to make smart manufacturing.

The rise of intelligent manufacturing and the changing trade environment make the transformation and upgrading of China’s manufacturing industry urgent.