preface

Today we bring a very cool work, still using the powerful HT for Web 3D graphics components, smooth performance, you can enjoy the effect first!

Click me in!

Code implementation

After finishing the scene, first we need to do some basic Settings for it, such as:

// Set the camera position
gv.setEye([457.9047.434])
// Set the center point position
gv.setCenter([4 -.- 1.0])
// Set the remote distance
gv.setFar(500000)
Copy the code

Setting this allows the scene to show the desired display Angle after deserialization. Setting the remote location can avoid problems such as incomplete scene display.

Enter the animation

To make it look like there is an entry process, we added an entry animation to spice up the scene:

ht.Default.startAnim({
    duration: 3000.// The number of milliseconds for the animation cycle. The Default is' hT.default. animDuration '
    action: function (v) { // The action function must be provided to implement property changes during animation.
        gv.setEye([gv.getEye()[0] + (1117 - gv.getEye()[0]) * (v / 5), gv.getEye()[1] + (450 - gv.getEye()[1]) * (v / 5), gv.getEye()[2] + (1139 - gv.getEye()[2]) * (v / 5)])},finishFunc: function () { // The function called after the animation ends.
        gv.scene = {
            eye: ht.Default.clone(gv.getEye()),
            center: ht.Default.clone(gv.getCenter()),
            far: ht.Default.clone(gv.getFar()),
            near: ht.Default.clone(gv.getNear())
        }
    }
})
Copy the code

Our idea for this animation is to achieve it by changing the position of the camera. We can complete the animation within the specified time period by using the animation function, which can be understood as the process of gradually changing some properties from the initial value to the target value. By fine-tuning carmera in the Action function, we can achieve perfect entry. In the finishFunc function, we do a copy operation to keep this location in mind for later implementation, which will be mentioned later.

The Angle of view control

Oh, and we also have to limit the Angle and scope of the scene:

var mapInteractor = new ht.graph3d.MapInteractor(gv)
gv.setInteractors([
    mapInteractor
])
gv.mp(function (e) {
    if (e.property === "eye") {
        if (gv.getEye()[0] > 3500) {
            gv.getEye()[0] = 3500
        }
        if (gv.getEye()[0] < - 3500.) {
            gv.getEye()[0] = - 3500.
        }
        if (gv.getEye()[1] > 9000) {
            gv.getEye()[1] = 9000
        }
        if (gv.getEye()[2] > 3500) {
            gv.getEye()[2] = 3500
        }
        if (gv.getEye()[2] < - 3500.) {
            gv.getEye()[2] = - 3500.}}})Copy the code

This limits the flip to the underside of the scene, and then limits the eye to prevent it from going beyond the skyball envelope when pulled out.

Next we will add a scene view reset function:

gv.mi(function (e) {
    if (e.kind === 'doubleClickBackground') {
        gv.moveCamera(gv.scene.eye, gv.scene.center, true)}... })Copy the code

The event monitor moves the center position via moveCamera() on the double click. The coordinates are the positions recorded in the action of the entry animation.

In order to enhance performance and convenience, we add another logic of control panel switch in click event, so that the display can be simplified:

if (e.kind === 'clickData') {
   if (e.data.getTag() === 'button') {
        var status = dm.getDataByTag('panel 1').s('3d.visible')
        for (var i = 1; i <= 10; i++) {
            dm.getDataByTag('panel' + i).s('3d.visible', !status)
        }
    }
}
Copy the code

The following effects can be achieved by changing the properties of the 2D panel:

Animation to achieve

Then we need to animate the flow of the pipeline, the operation of the track, the movement of the rotary kiln and the rotation of the grinding wheel.

function flow(name1, name2) {
    for (var i = 1; i <= 6; i++) {
        / / uv offset
        if (name2) {
            dm.getDataByTag(name2 + i).s('shape3d.uv.offset', [dm.getDataByTag(name2 + i).s('shape3d.uv.offset') [0] + 0.005, dm.getDataByTag(name2 + i).s('shape3d.uv.offset') [1]])}// Set the default value
        else {
            dm.getDataByTag(name1 + i).s('shape3d.uv.offset'[0.0])}}}/ / material storage tank
function tank(name, num, v) {
    for (var i = 1; i <= 8; i++) {
        dm.getDataByTag(name + i).setScaleTall(dm.getDataByTag(name + i).getScaleTall() + (num[i - 1] - dm.getDataByTag(name + i).getScaleTall()) * v)
    }
}
/ / roller
function roller(name) {
    for (var i = 1; i <= 12; i++) {
        if (i % 2= = =0) {
            value = 0.1
        }
        else {
            value = 0.1
        }
        if (i <= 8) {
            dm.getDataByTag(name + i).r3(dm.getDataByTag(name + i).r3()[0], dm.getDataByTag(name + i).r3()[1] + value, dm.getDataByTag(name + i).r3()[2])}else {
            dm.getDataByTag(name + i).r3(dm.getDataByTag(name + i).r3()[0] + value, dm.getDataByTag(name + i).r3()[1], dm.getDataByTag(name + i).r3()[2])
        }
    }
}
anim()
function anim() {
    var num = []
    for (var i = 1; i <= 8; i++) {
        num.push(Math.random() * 6)
    }
    ht.Default.startAnim({
        duration: 1000.action: function (v, t) {
            dm.getDataByTag(Flow '2').r3(dm.getDataByTag(Flow '2').r3()[0] - 0.1, dm.getDataByTag(Flow '2').r3()[1], dm.getDataByTag(Flow '2').r3()[2])
            flow('flow'.'flow')
            tank('Storage tank', num, v)
            roller('the wheel')},finishFunc: function () {
            anim()
        }
    })
}
Copy the code

I put them in a unified animation function to play in a loop. They are some relatively simple animations, and the corresponding animation effect can be achieved by changing the height, Angle and other attributes, as shown in the code. Here I will say a little bit about the implementation of the pipe and track flow, which I did by adjusting the UV map.

What is UV? Generally speaking, UV is to peel off the outer surface of the THREE-DIMENSIONAL model, expand and pave it into a two-dimensional plane state for mapping, just as the packaging pattern on cigarette boxes is actually printed in the state of paper boxes.

var truck1 = dm.getDataByTag(Truck '1')
var truck2 = dm.getDataByTag('the truck 2')
var truck3 = dm.getDataByTag('truck 3')
var cargo1 = dm.getDataByTag('goods bucket 1')
var cargo2 = dm.getDataByTag('goods bucket 2')
var coal = dm.getDataByTag(Goods' 1 ')
var limestone = dm.getDataByTag(Goods' 2 ')
var panel1 = dm.getDataByTag('panel 8')
var panel2 = dm.getDataByTag('panel 9')
anim1()
/ /
function anim1() {
    ht.Default.startAnim({
        duration: 4000.easing: function (t) { return (t *= 2) < 1 ? 0.5 * t * t : 0.5 * (1 - (--t) * (t - 2))},action: function (v, t) {
            truck1.p3(truck1.p3()[0], truck1.p3()[1], truck1.p3()[2] + (700 - truck1.p3()[2]) * (v / 10))
            truck2.p3(truck2.p3()[0], truck2.p3()[1], truck2.p3()[2] + (700 - truck2.p3()[2]) * (v / 5))
            truck3.p3(truck3.p3()[0] + (300 - truck3.p3()[0]) * (v / 20), truck3.p3()[1], truck3.p3()[2])},finishFunc: function () {
            anim2()
        }
    })
}
/ / turn around
function anim2() {
    ht.Default.startAnim({
        duration: 1000.action: function (v, t) {
            truck1.r3(truck1.r3()[0], truck1.r3()[1] + (180 * Math.PI / 180 - truck1.r3()[1]) * v, truck1.r3()[2])
            truck2.r3(truck2.r3()[0], truck2.r3()[1] + (180 * Math.PI / 180 - truck2.r3()[1]) * v, truck2.r3()[2])
            truck3.r3(truck3.r3()[0], truck3.r3()[1] + (- 90. * Math.PI / 180 - truck3.r3()[1]) *  v, truck3.r3()[2])},finishFunc: function () {
            anim3()
        }
    })
}
/ / unloading
function anim3() {
    ht.Default.startAnim({
        duration: 2000.action: function (v, t) {
            cargo1.r3(cargo1.r3()[0] + (70 * Math.PI / 180 - cargo1.r3()[0]) * v, cargo1.r3()[1],  cargo1.r3()[2])
            cargo2.r3(cargo2.r3()[0] + (70 * Math.PI / 180 - cargo2.r3()[0]) * v, cargo2.r3()[1],  cargo2.r3()[2])
            panel1.a('Progress value', panel1.a('Progress value') + (0 - panel1.a('Progress value')) * v)
            panel2.a('Progress value', panel2.a('Progress value') + (0 - panel2.a('Progress value')) * v)
            panel1.a('weight', panel1.a('Progress value').toFixed(1))
            panel2.a('weight', panel2.a('Progress value').toFixed(1))},finishFunc: function () {
            coal.s('3d.visible'.false)
            limestone.s('3d.visible'.false)
            anim4()
        }
    })
}
/ / unloading
function anim4() {
    ht.Default.startAnim({
        duration: 2000.action: function (v, t) {
            cargo1.r3(cargo1.r3()[0] + (0 * Math.PI / 180 - cargo1.r3()[0]) * v, cargo1.r3()[1],  cargo1.r3()[2])
            cargo2.r3(cargo2.r3()[0] + (0 * Math.PI / 180 - cargo2.r3()[0]) * v, cargo2.r3()[1],  cargo2.r3()[2])},finishFunc: function () {
            anim5()
        }
    })
}
/ / return
function anim5() {
    ht.Default.startAnim({
        duration: 4000.easing: function (t) { return (t *= 2) < 1 ? 0.5 * t * t : 0.5 * (1 - (--t) * (t - 2))},action: function (v, t) {
            truck1.p3(truck1.p3()[0], truck1.p3()[1], truck1.p3()[2] + (1180 - truck1.p3()[2]) * (v / 10))
            truck2.p3(truck2.p3()[0], truck2.p3()[1], truck2.p3()[2] + (1180 - truck2.p3()[2]) * (v / 5))
            truck3.p3(truck3.p3()[0] + (1180 - truck3.p3()[0]) * (v / 20), truck3.p3()[1], truck3.p3()[2])},finishFunc: function () {
            anim6()
        }
    })
}
/ / turn around
function anim6() {
    ht.Default.startAnim({
        duration: 1000.action: function (v, t) {
            truck1.r3(truck1.r3()[0], truck1.r3()[1] + (0 * Math.PI / 180 - truck1.r3()[1]) * v, truck1.r3()[2])
            truck2.r3(truck2.r3()[0], truck2.r3()[1] + (0 * Math.PI / 180 - truck2.r3()[1]) * v, truck2.r3()[2])
            truck3.r3(truck3.r3()[0], truck3.r3()[1] + (90 * Math.PI / 180 - truck3.r3()[1]) * v, truck3.r3()[2])},finishFunc: function () {
            panel1.a('Progress value'.1)
            panel2.a('Progress value'.1)
            panel1.a('weight'.10)
            panel2.a('weight'.10)
            coal.s('3d.visible'.true)
            limestone.s('3d.visible'.true)
            anim1()
        }
    })
}
Copy the code

This is my complete code for realizing the entire operation process of the truck, which is coordinated and combined by several pieces of animation respectively. It is not difficult as long as we understand the sequence and the logic of each action, which is nothing more than the calculation of direction, Angle and distance, as well as the synchronization setting of the progress bar on the panel.

conclusion

With the rapid development of the Concept of Internet +, there are so many fields waiting for us to explore. HT for Web is very suitable for various intelligent buildings, monitoring systems and industrial automation (HMI/SCADA) fields such as power and gas. Hope to read my article, we can be inspired to challenge more impossible!