preface
This is the first time for me to contact the tunnel project, and I feel the effect is quite good, so I would like to share it with you. The main contents of this tunnel project include: lighting, fan, lane indicator light, traffic signal light, information board, fire fighting, fire alarm, vehicle crossing hole, wind vane, COVI, microwave vehicle inspection and control of tunnel emergency exit. In this example, I will mainly talk about the animation Settings of the wind vane, exhaust air and escape exit, and click the traffic signal light, the popup window can select the information of the current signal light and other contents.
This example demonstrates the address: www.hightopo.com/demo/tunnel…
Effect picture of this example:
Project implementation
HT has a 3D component. You can create an instance directly by using the new HT.graph3d.graph3dView 3D component. Then you can use getView() to get the underlying div of the component. That position display control is much easier:
dm = new ht.DataModel(); // Data container, which can store all data displayed on the interface through datamodel.add
g3d = new ht.graph3d.Graph3dView(dm); / / 3 d component
g3d.addToDOM(); // Add the underlying DIV of the 3D component to the body
Copy the code
While HT components are typically embedded in containers such as BorderPane, SplitView, and TabView, the outermost HT components require the user to manually add the underlying div element returned by getView() to the DOM element of the page. When the parent container size changes, if the parent container is a predefined container component such as BorderPane and SplitView, the HT container automatically recursively calls the child component invalidate function to notify the update. However, if the parent container is a native HTML element, the HT component cannot know that it needs to be updated. Therefore, the outermost HT component usually needs to listen for the window size change event and call the invalidate function of the outermost component to update.
For ease of loading and filling Windows for the outermost components, all components of HT have addToDOM functions that implement the following logic, where iv is short for invalidate:
addToDOM = function(){
var self = this,
view = self.getView(), // Get the underlying div of the component
style = view.style;
document.body.appendChild(view); // Add the component's underlying div to the body
style.left = '0'; // The HT component sets position to absolute by default
style.right = '0';
style.top = '0';
style.bottom = '0';
window.addEventListener('resize'.function () { self.iv(); }, false);
}
Copy the code
Load the scene
Ht.default. xhrLoad is used to load the scene of json file directly, which makes me and the designer two processes. I am very happy. There are three steps to load scene:
ht.Default.xhrLoad('scenes/tunnel. Json'.function(text){ // Load the JSON scene
var json = ht.Default.parse(text); // Escape the JSON file
dm.deserialize(json); // Deserialize the JSON content into the scene
// You can manipulate the data in the datamodel container
}
Copy the code
Add animation
I added some functions in the scene, including the aforementioned some animation operation, HT encapsulated dataModel. AddScheduleTask dataModel (task) by manipulating the data container to control loading animation, animation part of the statement in the parameters of the task, Task is a JSON object. You can specify the following attributes:
- Interval: indicates the interval of milliseconds. The default value is 10
- Enabled: Whether to enable the switch. The default value is true
- Action: Interval action function, which must be set
There are three of my animations, one fan, one wind vane and one shutter in each tunnel. In JSON, I set the tag of these three primitors to Feng, feng2, and door respectively. In the code, I can directly call the tag attribute of these three primitors:
var task = {
action: function(data){
if(! data.getTag())return;
var tag = data.getTag(); // Get the tag attribute of the primitive
if(tag === 'feng'){
data.r3(0, (data.r3()[1] +Math.PI/12), 0); // R3 is the rotation in 3D, where the y axis is rotated by math.pi /12
}else if(tag === 'feng2'){
data.r3(0.0, data.r3()[2] +Math.PI/12);
}else if(tag === 'door') {if(data.getTall() > 0) {// Get the tall attribute of the pixel
data.setTall(data.getTall()- 20); // Set the height to the current height minus 20
}
}
}
}
dm.addScheduleTask(task); // Add the scheduling task in the data container dataModel
Copy the code
Adding an information form
Then create the form form and add some information to the form, such as the switch of traffic lights, etc. By default, we will not explain the form form in the upper right corner of the scene. The content is similar to the form form that appears when clicking traffic lights, so we will mainly explain the form that appears when clicking traffic lights:
There are a lot of duplicated parts in the form, so I’ll pick out three parts to explain: the text part, the icon displayed in the “current state” and the icon click selection part in the “Modify State” below:
form.addRow([ // addRow adds a line to my section to add a title
{
element: 'Traffic light control'.// Display text for the first part of this line
align: 'center'.// Text alignment
color: 'RGB (0210187)..// Text color
font: 'bold 16px arial, sans-serif' // Text font}], [0.1]); // Remember to set the width of this line
form.addRow([ // There are two parts in this line, a "device description" and a text "0", so set two widths, and put the widths in an array
'Device Description :'.// The first part
{ // Part 2
element: '0'.color: 'RGB (0210187).
}
],[80.0.1].34); // The second argument to the addRow function is to set the width. The third parameter is height
form.addRow([
Current status:,
{ // You can also set some part of the array to an empty string that takes up some width. This ratio is easier to adjust
element: ' '
},
{
id: '105'.// id uniquely identifies attributes that can be added to the corresponding item object via formpane.getitembyId (id)
button: { // Button, which automatically builds an HT.widget. Button object based on the property value and saves it on the Element property
icon: 'Symbols/tunnel ICONS /light.json'.// The display icon on the button
background: 'rgba (0,7,26,0.60)'.// Button background
borderColor: 'rgb(0, 7, 26)'.// Button border color
clickable: false // Is it clickable}}], [80.0.1.84].30);
form.addRow([ // If the distance between the top line and the other lines is different, you can set the height by adding a blank line
' ',
{
element: ' '}], [200.0.1].10);
form.addRow([
'Modify status :',
{
element: ' '
},
{
button: {
icon: 'Symbols/tunnel ICONS /light.json'.// Set the button icon
background: 'rgba (0,7,26,0.60)'.borderColor: 'rgb(0, 7, 26)'.groupId: 'btn'.// Use getGroupId and setGroupId to get and set the group number. Togglable buttons belonging to the same group are mutually exclusive. The next three buttons also set the same groupId
onClicked: function(e){ // Click the callback function
btnClick('light'); }}}], [80.0.1.84].30);
Copy the code
The background of this form is just an image:
background: url('assets/control. PNG') no-repeat;
Copy the code
There is another part not mentioned above, which is the btnClick function called after clicking the button:
function btnClick(imageName){
if(flag === 1) {// The judgments are made based on 3d events, which will be mentioned later
dm.getDataByTag('light').s({ // Get the node with getDataByTag and set the style of the node
'back.image': 'Symbols/tunnel ICONS /'+imageName+'.json'.// Set the back image of the primitives
'front.image': 'Symbols/tunnel ICONS /'+imageName+'.json' // Set the pixel in front of your image
});
}else if(flag === 2){
dm.getDataByTag('light1').s({
'back.image': 'Symbols/tunnel ICONS /'+imageName+'.json'.'front.image': 'Symbols/tunnel ICONS /'+imageName+'.json'
});
}else{}
form.getViewById(105).setIcon('Symbols/tunnel ICONS /'+imageName+'.json'); // Set the display icon of the item content with id 105 to the icon of the traffic light button clicked on the form
}
Copy the code
Click on the event
Finally, there are click events, one is the traffic light control form after clicking the traffic light in 3D, and another is the icon event in “modify status” on the form form:
g3d.mi(function(e){ // The addInteractorListener function listens for events in the scenario
form.getView().style.display = 'none'; // All click primitives hide the form first
if(e.kind === 'clickData') {// Click the icon
if(e.data.getTag() === 'light') {// If the primitives are positive tunnel lights
form.getView().style.display = 'block'; // Display the form form
form.iv(); // Refresh the form form, otherwise the interface cannot be learned
flag = 1;
}else if(e.data.getTag() === 'light1') {// In the back of the tunnel, click to switch the display of the lights in the tunnel, the lights in the other tunnel can not be changed together, so it must be separated
form.getView().style.display = 'block';
form.iv();
flag = 2;
}else if(e.data.getTag() === 'wall') {// Tunnel wall
e.data.s({
'shape3d.transparent': true.// Turn on the transparency switch
'shape3d.opacity': 0.2.// Set transparency
'3d.selectable': false // The tunnel will not be selected}); }}else if(e.kind === 'doubleClickBackground') {// Click the blank area to set the tunnel wall opacity
dm.getDatas().forEach(function(data){ / / traverse dataModel
if(data.getTag() === 'wall'){
data.s({
'shape3d.transparent': false.// Turn off the transparency switch, so that transparency is not controlled
'3d.selectable': true // Double click on the space to make the tunnel selectable}); }}); }});Copy the code
In this paper, examples address: www.hightopo.com/demo/tunnel…