{"id":391,"date":"2015-01-12T19:16:16","date_gmt":"2015-01-12T11:16:16","guid":{"rendered":"http:\/\/www.hightopo.com\/blog\/?p=391"},"modified":"2015-01-12T19:16:16","modified_gmt":"2015-01-12T11:16:16","slug":"ht-for-web-3d%e6%b8%b8%e6%88%8f%e8%ae%be%e8%ae%a1%e8%ae%be%e8%ae%a1-%e6%b1%89%e8%af%ba%e5%a1%94%ef%bc%88towers-of-hanoi%ef%bc%89","status":"publish","type":"post","link":"https:\/\/www.hightopo.com\/blog\/391.html","title":{"rendered":"HT for Web 3D\u6e38\u620f\u8bbe\u8ba1\u8bbe\u8ba1&#8211;\u6c49\u8bfa\u5854\uff08Towers of Hanoi\uff09"},"content":{"rendered":"<p>\u5728\u8fd9\u91cc\u6211\u4eec\u5c06\u6784\u9020\u4e00\u4e2a\u57fa\u4e8eHT for Web\u7684HTML5+JavaScript\u6765\u5b9e\u73b0\u6c49\u8bfa\u5854\u6e38\u620f\u3002<\/p>\n<p>\u6c49\u8bfa\u5854\u7684\u6e38\u620f\u89c4\u5219\u53ca\u9012\u5f52\u7b97\u6cd5\u5206\u6790\u8bf7\u53c2\u8003<a href=\"http:\/\/en.wikipedia.org\/wiki\/Tower_of_Hanoi\">http:\/\/en.wikipedia.org\/wiki\/Tower_of_Hanoi<\/a>\u3002<\/p>\n<p>\u77e5\u9053\u4e86\u6c49\u8bfa\u5854\u7684\u89c4\u5219\u548c\u7b97\u6cd5\uff0c\u73b0\u5728\u5c31\u5f00\u59cb\u521b\u5efa\u5143\u7d20\u3002\u7528HT for Web\uff08<a href=\"http:\/\/www.hightopo.com\/\" target=\"_blank\">http:\/\/www.hightopo.com<\/a>\uff09\u73b0\u6709\u76843D\u6a21\u677f\u521b\u5efa\u5e95\u76d8\u548c3\u6839\u67f1\u5b50\u4e0d\u662f\u95ee\u9898\uff0c\u95ee\u9898\u662f\u8981\u521b\u5efa\u82e5\u5e72\u4e2a\u4e2d\u7a7a\u7684\u5706\u76d8\u3002\u4e00\u5f00\u59cb\u7684\u60f3\u6cd5\u662f\uff1a\u521b\u5efa\u4e00\u4e2a\u5706\u67f1\u4f53\uff0c\u5c06\u5706\u67f1\u4f53\u7684\u4e0a\u4e0b\u4e24\u7aef\u9690\u85cf\uff0c\u8bbe\u7f6e\u67f1\u9762\u7684\u5bbd\u5ea6\u6765\u5b9e\u73b0\u5706\u76d8\u7684\u6548\u679c\uff0c\u7ecf\u8fc7\u591a\u6b21\u5c1d\u8bd5\u5e76\u67e5\u9605\u76f8\u5173api\u6587\u6863\uff0c\u53d1\u73b0\u67f1\u9762\u662f\u6ca1\u6709\u539a\u5ea6\u7684\uff0c\u6539\u65b9\u6cd5\u4e0d\u53ef\u884c\u3002<\/p>\n<p>\u540e\u6765\u5728HT for Web\u81ea\u5b9a\u4e493D\u6a21\u578b\u7684WebGL\u5e94\u7528\uff08<a href=\"http:\/\/www.hightopo.com\/blog\/381.html\">http:\/\/www.hightopo.com\/blog\/381.html<\/a>\uff09\u53d7\u5230\u542f\u53d1\uff0c\u5706\u76d8\u7684\u5f62\u6210\u5c31\u662f\u5728xy\u5e73\u9762\u4e0a\u7684\u4e00\u4e2a\u77e9\u5f62\uff0c\u6839\u636ey\u8f74\u65cb\u8f6c\u4e00\u5468\u4ea7\u751f\u7684\uff0c\u901a\u8fc7\u67e5\u9605\u76f8\u5173\u6587\u6863\uff0c\u6700\u603b\u51b3\u5b9a\u91c7\u7528ht.Default.createRingModel\u65b9\u6cd5\u6765\u521b\u5efa\u5706\u76d8\u6a21\u578b\uff0c\u7136\u540e\u5728\u521b\u5efanode\u7684\u65f6\u5019\u901a\u8fc7shape3d\u5c5e\u6027\u5f15\u7528\u521b\u5efa\u597d\u7684\u6a21\u578b\u3002<\/p>\n<p><img alt=\"\" src=\"http:\/\/images.cnitblog.com\/blog\/712891\/201501\/121707539954373.png\" \/><\/p>\n<p>\u5728\u903b\u8f91\u5b9e\u73b0\u4e0a\uff0c\u91c7\u7528\u4e86\u6808\u7684\u5148\u8fdb\u540e\u51fa\u7684\u539f\u7406\uff0c\u5bf9\u5706\u67f1\u4e0a\u7684\u5706\u76d8\u505a\u987a\u5e8f\u63a7\u5236\uff0c\u786e\u4fdd\u6bcf\u6b21\u79fb\u52a8\u7684\u5706\u76d8\u90fd\u662f\u6700\u5c0f\u7684\u5706\u76d8\u3002<\/p>\n<p>\u5728\u7b97\u6cd5\u4e0a\uff0c\u91c7\u7528\u7684\u662f\u9012\u5f52\u7b97\u6cd5\uff0c\u901a\u8fc7\u9012\u5f52\u7b97\u6cd5\uff0c\u5c06\u642c\u8fc1\u8fc7\u7a0b\u4e00\u6b65\u4e00\u6b65\u8bb0\u5f55\u4e0b\u6765\uff0c\u518d\u91c7\u7528\u5806\u7684\u539f\u7406\u4e00\u6b65\u4e00\u6b65\u5730\u6267\u884c\u642c\u8fc1\u8fc7\u5de5\u4f5c\u3002<\/p>\n<p><img loading=\"lazy\" alt=\"\" src=\"http:\/\/images.cnitblog.com\/blog\/712891\/201501\/121708207453267.png\" width=\"781\" height=\"436\" \/><\/p>\n<p><iframe height=498 width=510 src=\"http:\/\/player.youku.com\/embed\/XODcwMTk4MDI4\" frameborder=0 allowfullscreen><\/iframe><\/p>\n<pre class='brush:javascript'>\r\nvar barNum = 5, \/\/ \u5706\u76d8\u4e2a\u6570\r\n    cylinderHeight = barNum * 20 + 40, \/\/ \u5706\u67f1\u9ad8\u5ea6\r\n    barrelMinORadius  = 50, \/\/ \u5706\u76d8\u6700\u5927\u5916\u534a\u5f84\r\n    barrelIRadius = 10, \/\/ \u5706\u76d8\u5185\u534a\u5f84\r\n    poorRadius = 20, \/\/ \u5706\u76d8\u5916\u534a\u5f84\u5dee\u503c\r\n    barrelMaxORadius = barrelMinORadius + barNum * poorRadius,\r\n    barrelHeight = 20, \/\/ \u5706\u76d8\u9ad8\r\n    barPadding = 20, \/\/ \u67f1\u4f53\u4e4b\u95f4\u7684\u95f4\u9699\r\n    floorX = barrelMaxORadius * 6 + barPadding * 4, \/\/ \u5e95\u76d8\u957f\r\n    floorY = 20, \/\/ \u5e95\u76d8\u9ad8\r\n    floorZ = 2 * barrelMaxORadius + barPadding * 2, \/\/ \u5e95\u76d8\u5bbd\r\n    \/\/ \u67f1\u4f53\u96c6\r\n    positions = [\r\n        {\r\n            barrels: [],\r\n            position: [-(2*barrelMaxORadius + barPadding), cylinderHeight \/ 2 + 1, 0]\r\n        },{\r\n            barrels: [],\r\n            position: [0, cylinderHeight \/ 2 + 1, 0]\r\n        },{\r\n            barrels: [],\r\n            position: [(2*barrelMaxORadius + barPadding), cylinderHeight \/ 2 + 1, 0]\r\n        }\r\n    ],\r\n    runOrder = [], \/\/ \u5706\u76d8\u79fb\u52a8\u987a\u5e8f\u96c6\r\n    \/\/ \u52a8\u753b\u53c2\u6570\r\n    params = {\r\n        delay: 10,\r\n        duration: 500,\r\n        easing: Easing['easeBoth']\r\n    };\r\n\r\n\/**\r\n * \u521d\u59cb\u5316\u7a0b\u5e8f\r\n * *\/\r\nfunction init(){\r\n    dataModel = new ht.DataModel();\r\n    g3d = new ht.graph3d.Graph3dView(dataModel);\r\n    view = g3d.getView();\r\n    view.className = 'main';\r\n    document.body.appendChild(view);\r\n    window.addEventListener('resize', function (e) {\r\n        g3d.invalidate();\r\n    }, false);\r\n\r\n    g3d.setEye([0, cylinderHeight * 2, floorX * sin(2*PI\/360*60)]);\r\n\r\n    \/\/ \u521d\u59cb\u5316\u8282\u70b9\r\n    initNodes();\r\n\r\n    moveAnimation();\r\n}\r\n\r\n\/**\r\n * \u6784\u9020\u6e38\u620f\u79fb\u52a8\u961f\u5217\r\n * diskQuantity\uff1a\u5706\u76d8\u4e2a\u6570\r\n * positionA\uff1a\u8d77\u70b9\r\n * positionB\uff1a\u4e2d\u8f6c\u70b9\r\n * positionC\uff1a\u7ec8\u70b9\r\n * *\/\r\nfunction buildRunOrder(diskQuantity, positionA, positionB, positionC){\r\n    if (diskQuantity == 1) {\r\n        runOrder.push([positionA, positionC]);\r\n    } else {\r\n        buildRunOrder(diskQuantity - 1, positionA, positionC, positionB);\r\n        buildRunOrder(1, positionA, positionB, positionC);\r\n        buildRunOrder(diskQuantity - 1, positionB, positionA, positionC);\r\n    }\r\n}\r\n\r\n\/**\r\n * \u79fb\u52a8\u52a8\u753b\r\n * positionA\uff1a\u8d77\u70b9\r\n * positionC\uff1a\u7ec8\u70b9\r\n * *\/\r\nfunction moveAnimation(positionA, positionC){\r\n    if(!positionA){\r\n        var poses = runOrder.shift();\r\n        if(!poses){\r\n            setTimeout(reset, 500);\r\n        }else{\r\n            moveAnimation(positions[poses[0]], positions[poses[1]]);\r\n        }\r\n    }else {\r\n        var barrel = positionA.barrels.pop();\r\n        var position = positionC.cylinder.p3(),\r\n            barPos = barrel.getPosition3d();\r\n        position[1] = position[1] + floorY + barrelHeight * positionC.barrels.length - cylinderHeight \/ 2;\r\n        setPolylinePoints(polyline, barPos, position);\r\n        params.action = function (v, t) {\r\n            var length = g3d.getLineLength(polyline),\r\n                offset = g3d.getLineOffset(polyline, length * v),\r\n                point = offset.point,\r\n                px = point.x,\r\n                py = point.y,\r\n                pz = point.z;\r\n            barrel.p3(px, py, pz);\r\n        };\r\n        params.finishFunc = function () {\r\n            positionC.barrels.push(barrel);\r\n            var poses = runOrder.shift();\r\n            if (!poses) {\r\n                moveAnimation();\r\n            } else {\r\n                moveAnimation(positions[poses[0]], positions[poses[1]]);\r\n            }\r\n        };\r\n        anim = ht.Default.startAnim(params);\r\n    }\r\n}\r\n\r\n\/**\r\n * \u91cd\u7f6e\u6e38\u620f\r\n * *\/\r\nfunction reset(){\r\n    if(positions[0].barrels.length == 0){\r\n        positions[0].barrels = positions[2].barrels;\r\n    }\r\n    positions[2].barrels = [];\r\n    for(var i = 0, len = positions[0].barrels.length; i < len; i++){\r\n        var pos = positions[0].cylinder.p3();\r\n        pos[1] = pos[1] + floorY + i * barrelHeight - cylinderHeight \/ 2;\r\n        positions[0].barrels[i].p3(pos);\r\n    }\r\n    buildRunOrder(barNum, 0, 1, 2);\r\n    setTimeout(moveAnimation, 500);\r\n}\r\n\r\n\/**\r\n * \u521d\u59cb\u5316\u8282\u70b9\r\n * *\/\r\nfunction initNodes(){\r\n    \/\/ \u5e95\u76d8\r\n    floor = createNode([0, floorY \/ 2, 0], [floorX, floorY, floorZ]).s({\r\n        'shape3d':  'box',\r\n        '3d.movable': false\r\n    });\r\n\r\n    \/\/ \u521b\u5efa\u67f1\u5b50\r\n    for(var i = 0, len = 3; i < len; i++){\r\n        positions[i].cylinder = createNode(positions[i].position, [20, cylinderHeight, 20], floor).s({\r\n            'shape3d':  'cylinder',\r\n            'shape3d.color': '#E5BB77',\r\n            '3d.movable': false\r\n        });\r\n    }\r\n\r\n    \/\/ \u521b\u5efa\u5706\u76d8\r\n    createBarrels(barNum, positions[0].cylinder);\r\n\r\n    \/\/ \u521b\u5efa\u5706\u76d8\u8fd0\u884c\u8f68\u8ff9\r\n    polyline = new ht.Polyline();\r\n    polyline.setSegments([1, 2, 4, 2]);\r\n    polyline.s({\r\n        'shape.background': null,\r\n        'shape.border.color': 'rgba(0,0,0,0)',\r\n        'shape.border.gradient.color': 'rgba(0,0,0,0)',\r\n        'shape.border.pattern': [20, 10],\r\n        'shape3d.resolution': 50\r\n    });\r\n    dataModel.add(polyline);\r\n}\r\n\r\n\/**\r\n * \u8bbe\u7f6e\u8def\u7ebf\u8282\u70b9\r\n * *\/\r\nfunction setPolylinePoints(polyline, from, to){\r\n    polyline.setPoints([\r\n        {x: from[0], y: from[2], e: from[1]},\r\n        {x: from[0], y: from[2], e: cylinderHeight},\r\n        {x: from[0], y: from[2], e: cylinderHeight + 60},\r\n        {x: to[0], y: to[2], e: cylinderHeight + 60},\r\n        {x: to[0], y: to[2], e: cylinderHeight},\r\n        {x: to[0], y: to[2], e: to[1]}\r\n    ]);\r\n    return polyline;\r\n}\r\n\r\n\/**\r\n * \u521b\u5efa\u5706\u76d8\r\n * barNum\uff1a\u5706\u76d8\u4e2a\u6570\r\n * host\uff1a\u5438\u9644\u8282\u70b9\r\n * *\/\r\nfunction createBarrels(barNum, host){\r\n    \/\/ \u5706\u76d8\u521d\u59cbx\u4f4d\u7f6e\r\n    var pos = host.p3();\r\n\r\n    for(var i = barNum, j = 0; i > 0; i--, j++){\r\n        pos[1] = barrelHeight * j + floorY;\r\n        positions[0].barrels.push(createBarrel(pos, [1, barrelHeight, 1], barrelMinORadius + i*poorRadius, barrelIRadius, host).s({\r\n            'shape3d.color': randomColor(),\r\n            '3d.movable': false\r\n        }));\r\n    }\r\n}\r\n\r\n\/**\r\n * \u521b\u5efa\u8282\u70b9\r\n * p3\uff1a\u8282\u70b9\u4f4d\u7f6e\r\n * s3\uff1a\u8282\u70b9\u5927\u5c0f\r\n * host\uff1a\u5438\u9644\u8282\u70b9\r\n * *\/\r\nfunction createNode(p3, s3, host){\r\n    var node = new ht.Node();\r\n    node.p3(p3);\r\n    node.s3(s3);\r\n    node.setHost(host);\r\n    node.s({\r\n        'wf.visible': 'selected',\r\n        'wf.color': '#FF6B10',\r\n        'wf.width': 2,\r\n        'wf.short': true\r\n    });\r\n    dataModel.add(node);\r\n    return node;\r\n}\r\n\r\n\/**\r\n * \u521b\u5efa\u7a7a\u5fc3\u5706\u67f1\r\n * p3\uff1a\u5706\u6876\u4f4d\u7f6e\r\n * s3\uff1a\u5706\u6876\u5927\u5c0f\r\n * oRadius\uff1a\u5706\u6876\u5916\u5f84\r\n * iRadius\uff1a\u5706\u6876\u5185\u5f84\r\n * host\uff1a\u5438\u9644\u8282\u70b9\r\n * *\/\r\nfunction createBarrel(p3, s3, oRadius, iRadius, host){\r\n    return createNode(p3, s3, host).s({\r\n        'shape3d':  ht.Default.createRingModel([\r\n            oRadius, 1,\r\n            oRadius, 0,\r\n            iRadius, 0,\r\n            iRadius, 1,\r\n            oRadius, 1\r\n        ], null, 20, false, false, 70)\r\n    });\r\n}\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>\u5728\u8fd9\u91cc\u6211\u4eec\u5c06\u6784\u9020\u4e00\u4e2a\u57fa\u4e8eHT for Web\u7684HTML5+JavaScript\u6765\u5b9e\u73b0\u6c49\u8bfa\u5854\u6e38\u620f\u3002<\/p>\n<p>\u6c49\u8bfa\u5854\u7684\u6e38\u620f\u89c4\u5219\u53ca\u9012\u5f52\u7b97\u6cd5\u5206\u6790\u8bf7\u53c2\u8003<a href=\"http:\/\/en.wikipedia.org\/wiki\/Tower_of_Hanoi\">http:\/\/en.wikipedia.org\/wiki\/Tower_of_Hanoi<\/a>\u3002<\/p>\n<p>\u77e5\u9053\u4e86\u6c49\u8bfa\u5854\u7684\u89c4\u5219\u548c\u7b97\u6cd5\uff0c\u73b0\u5728\u5c31\u5f00\u59cb\u521b\u5efa\u5143\u7d20\u3002\u7528HT for Web\uff08<a href=\"http:\/\/www.hightopo.com\/\" target=\"_blank\">http:\/\/www.hightopo.com<\/a>\uff09\u73b0\u6709\u76843D\u6a21\u677f\u521b\u5efa\u5e95\u76d8\u548c3\u6839\u67f1\u5b50\u4e0d\u662f\u95ee\u9898\uff0c\u95ee\u9898\u662f\u8981\u521b\u5efa\u82e5\u5e72\u4e2a\u4e2d\u7a7a\u7684\u5706\u76d8\u3002\u4e00\u5f00\u59cb\u7684\u60f3\u6cd5\u662f\uff1a\u521b\u5efa\u4e00\u4e2a\u5706\u67f1\u4f53\uff0c\u5c06\u5706\u67f1\u4f53\u7684\u4e0a\u4e0b\u4e24\u7aef\u9690\u85cf\uff0c\u8bbe\u7f6e\u67f1\u9762\u7684\u5bbd\u5ea6\u6765\u5b9e\u73b0\u5706\u76d8\u7684\u6548\u679c\uff0c\u7ecf\u8fc7\u591a\u6b21\u5c1d\u8bd5\u5e76\u67e5\u9605\u76f8\u5173api\u6587\u6863\uff0c\u53d1\u73b0\u67f1\u9762\u662f\u6ca1\u6709\u539a\u5ea6\u7684\uff0c\u6539\u65b9\u6cd5\u4e0d\u53ef\u884c\u3002<\/p>\n<p>\u540e\u6765\u5728HT for Web\u81ea\u5b9a\u4e493D\u6a21\u578b\u7684WebGL\u5e94\u7528\uff08<a href=\"http:\/\/www.hightopo.com\/blog\/381.html\">http:\/\/www.hightopo.com\/blog\/381.html<\/a>\uff09\u53d7\u5230\u542f\u53d1\uff0c\u5706\u76d8\u7684\u5f62\u6210\u5c31\u662f\u5728xy\u5e73\u9762\u4e0a\u7684\u4e00\u4e2a\u77e9\u5f62\uff0c\u6839\u636ey\u8f74\u65cb\u8f6c\u4e00\u5468\u4ea7\u751f\u7684\uff0c\u901a\u8fc7\u67e5\u9605\u76f8\u5173\u6587\u6863\uff0c\u6700\u603b\u51b3\u5b9a\u91c7\u7528ht.Default.createRingModel\u65b9\u6cd5\u6765\u521b\u5efa\u5706\u76d8\u6a21\u578b\uff0c\u7136\u540e\u5728\u521b\u5efanode\u7684\u65f6\u5019\u901a\u8fc7shape3d\u5c5e\u6027\u5f15\u7528\u521b\u5efa\u597d\u7684\u6a21\u578b\u3002<\/p>\n<p><img alt=\"\" src=\"http:\/\/images.cnitblog.com\/blog\/712891\/201501\/121707539954373.png\" \/><\/p>\n<p>\u5728\u903b\u8f91\u5b9e\u73b0\u4e0a\uff0c\u91c7\u7528\u4e86\u6808\u7684\u5148\u8fdb\u540e\u51fa\u7684\u539f\u7406\uff0c\u5bf9\u5706\u67f1\u4e0a\u7684\u5706\u76d8\u505a\u987a\u5e8f\u63a7\u5236\uff0c\u786e\u4fdd\u6bcf\u6b21\u79fb\u52a8\u7684\u5706\u76d8\u90fd\u662f\u6700\u5c0f\u7684\u5706\u76d8\u3002<\/p>\n<p>\u5728\u7b97\u6cd5\u4e0a\uff0c\u91c7\u7528\u7684\u662f\u9012\u5f52\u7b97\u6cd5\uff0c\u901a\u8fc7\u9012\u5f52\u7b97\u6cd5\uff0c\u5c06\u642c\u8fc1\u8fc7\u7a0b\u4e00\u6b65\u4e00\u6b65\u8bb0\u5f55\u4e0b\u6765\uff0c\u518d\u91c7\u7528\u5806\u7684\u539f\u7406\u4e00\u6b65\u4e00\u6b65\u5730\u6267\u884c\u642c\u8fc1\u8fc7\u5de5\u4f5c\u3002<\/p>\n<p><img loading=\"lazy\" alt=\"\" src=\"http:\/\/images.cnitblog.com\/blog\/712891\/201501\/121708207453267.png\" width=\"781\" height=\"436\" \/><\/p>\n<p><iframe height=498 width=510 src=\"http:\/\/player.youku.com\/embed\/XODcwMTk4MDI4\" frameborder=0 allowfullscreen><\/iframe><\/p>\n<pre class='brush:javascript'>\r\nvar barNum = 5, \/\/ \u5706\u76d8\u4e2a\u6570\r\n    cylinderHeight = barNum * 20 + 40, \/\/ \u5706\u67f1\u9ad8\u5ea6\r\n    barrelMinORadius  = 50, \/\/ \u5706\u76d8\u6700\u5927\u5916\u534a\u5f84\r\n    barrelIRadius = 10, \/\/ \u5706\u76d8\u5185\u534a\u5f84\r\n    poorRadius = 20, \/\/ \u5706\u76d8\u5916\u534a\u5f84\u5dee\u503c\r\n    barrelMaxORadius = barrelMinORadius + barNum * poorRadius,\r\n    barrelHeight = 20, \/\/ \u5706\u76d8\u9ad8\r\n    barPadding = 20, \/\/ \u67f1\u4f53\u4e4b\u95f4\u7684\u95f4\u9699\r\n    floorX = barrelMaxORadius * 6 + barPadding * 4, \/\/ \u5e95\u76d8\u957f\r\n    floorY = 20, \/\/ \u5e95\u76d8\u9ad8\r\n    floorZ = 2 * barrelMaxORadius + barPadding * 2, \/\/ \u5e95\u76d8\u5bbd\r\n    \/\/ \u67f1\u4f53\u96c6\r\n    positions = [\r\n        {\r\n            barrels: [],\r\n            position: [-(2*barrelMaxORadius + barPadding), cylinderHeight \/ 2 + 1, 0]\r\n        },{\r\n            barrels: [],\r\n            position: [0, cylinderHeight \/ 2 + 1, 0]\r\n        },{\r\n            barrels: [],\r\n            position: [(2*barrelMaxORadius + barPadding), cylinderHeight \/ 2 + 1, 0]\r\n        }\r\n    ],\r\n    runOrder = [], \/\/ \u5706\u76d8\u79fb\u52a8\u987a\u5e8f\u96c6\r\n    \/\/ \u52a8\u753b\u53c2\u6570\r\n    params = {\r\n        delay: 10,\r\n        duration: 500,\r\n        easing: Easing['easeBoth']\r\n    };\r\n\r\n\/**\r\n * \u521d\u59cb\u5316\u7a0b\u5e8f\r\n * *\/\r\nfunction init(){\r\n    dataModel = new ht.DataModel();\r\n    g3d = new ht.graph3d.Graph3dView(dataModel);\r\n    view = g3d.getView();\r\n    view.className = 'main';\r\n    document.body.appendChild(view);\r\n    window.addEventListener('resize', function (e) {\r\n        g3d.invalidate();\r\n    }, false);\r\n\r\n    g3d.setEye([0, cylinderHeight * 2, floorX * sin(2*PI\/360*60)]);\r\n\r\n    \/\/ \u521d\u59cb\u5316\u8282\u70b9\r\n    initNodes();\r\n\r\n    moveAnimation();\r\n}\r\n\r\n\/**\r\n * \u6784\u9020\u6e38\u620f\u79fb\u52a8\u961f\u5217\r\n * diskQuantity\uff1a\u5706\u76d8\u4e2a\u6570\r\n * positionA\uff1a\u8d77\u70b9\r\n * positionB\uff1a\u4e2d\u8f6c\u70b9\r\n * positionC\uff1a\u7ec8\u70b9\r\n * *\/\r\nfunction buildRunOrder(diskQuantity, positionA, positionB, positionC){\r\n    if (diskQuantity == 1) {\r\n        runOrder.push([positionA, positionC]);\r\n    } else {\r\n        buildRunOrder(diskQuantity - 1, positionA, positionC, positionB);\r\n        buildRunOrder(1, positionA, positionB, positionC);\r\n        buildRunOrder(diskQuantity - 1, positionB, positionA, positionC);\r\n    }\r\n}\r\n\r\n\/**\r\n * \u79fb\u52a8\u52a8\u753b\r\n * positionA\uff1a\u8d77\u70b9\r\n * positionC\uff1a\u7ec8\u70b9\r\n * *\/\r\nfunction moveAnimation(positionA, positionC){\r\n    if(!positionA){\r\n        var poses = runOrder.shift();\r\n        if(!poses){\r\n            setTimeout(reset, 500);\r\n        }else{\r\n            moveAnimation(positions[poses[0]], positions[poses[1]]);\r\n        }\r\n    }else {\r\n        var barrel = positionA.barrels.pop();\r\n        var position = positionC.cylinder.p3(),\r\n            barPos = barrel.getPosition3d();\r\n        position[1] = position[1] + floorY + barrelHeight * positionC.barrels.length - cylinderHeight \/ 2;\r\n        setPolylinePoints(polyline, barPos, position);\r\n        params.action = function (v, t) {\r\n            var length = g3d.getLineLength(polyline),\r\n                offset = g3d.getLineOffset(polyline, length * v),\r\n                point = offset.point,\r\n                px = point.x,\r\n                py = point.y,\r\n                pz = point.z;\r\n            barrel.p3(px, py, pz);\r\n        };\r\n        params.finishFunc = function () {\r\n            positionC.barrels.push(barrel);\r\n            var poses = runOrder.shift();\r\n            if (!poses) {\r\n                moveAnimation();\r\n            } else {\r\n                moveAnimation(positions[poses[0]], positions[poses[1]]);\r\n            }\r\n        };\r\n        anim = ht.Default.startAnim(params);\r\n    }\r\n}\r\n\r\n\/**\r\n * \u91cd\u7f6e\u6e38\u620f\r\n * *\/\r\nfunction reset(){\r\n    if(positions[0].barrels.length == 0){\r\n        positions[0].barrels = positions[2].barrels;\r\n    }\r\n    positions[2].barrels = [];\r\n    for(var i = 0, len = positions[0].barrels.length; i < len; i++){\r\n        var pos = positions[0].cylinder.p3();\r\n        pos[1] = pos[1] + floorY + i * barrelHeight - cylinderHeight \/ 2;\r\n        positions[0].barrels[i].p3(pos);\r\n    }\r\n    buildRunOrder(barNum, 0, 1, 2);\r\n    setTimeout(moveAnimation, 500);\r\n}\r\n\r\n\/**\r\n * \u521d\u59cb\u5316\u8282\u70b9\r\n * *\/\r\nfunction initNodes(){\r\n    \/\/ \u5e95\u76d8\r\n    floor = createNode([0, floorY \/ 2, 0], [floorX, floorY, floorZ]).s({\r\n        'shape3d':  'box',\r\n        '3d.movable': false\r\n    });\r\n\r\n    \/\/ \u521b\u5efa\u67f1\u5b50\r\n    for(var i = 0, len = 3; i < len; i++){\r\n        positions[i].cylinder = createNode(positions[i].position, [20, cylinderHeight, 20], floor).s({\r\n            'shape3d':  'cylinder',\r\n            'shape3d.color': '#E5BB77',\r\n            '3d.movable': false\r\n        });\r\n    }\r\n\r\n    \/\/ \u521b\u5efa\u5706\u76d8\r\n    createBarrels(barNum, positions[0].cylinder);\r\n\r\n    \/\/ \u521b\u5efa\u5706\u76d8\u8fd0\u884c\u8f68\u8ff9\r\n    polyline = new ht.Polyline();\r\n    polyline.setSegments([1, 2, 4, 2]);\r\n    polyline.s({\r\n        'shape.background': null,\r\n        'shape.border.color': 'rgba(0,0,0,0)',\r\n        'shape.border.gradient.color': 'rgba(0,0,0,0)',\r\n        'shape.border.pattern': [20, 10],\r\n        'shape3d.resolution': 50\r\n    });\r\n    dataModel.add(polyline);\r\n}\r\n\r\n\/**\r\n * \u8bbe\u7f6e\u8def\u7ebf\u8282\u70b9\r\n * *\/\r\nfunction setPolylinePoints(polyline, from, to){\r\n    polyline.setPoints([\r\n        {x: from[0], y: from[2], e: from[1]},\r\n        {x: from[0], y: from[2], e: cylinderHeight},\r\n        {x: from[0], y: from[2], e: cylinderHeight + 60},\r\n        {x: to[0], y: to[2], e: cylinderHeight + 60},\r\n        {x: to[0], y: to[2], e: cylinderHeight},\r\n        {x: to[0], y: to[2], e: to[1]}\r\n    ]);\r\n    return polyline;\r\n}\r\n\r\n\/**\r\n * \u521b\u5efa\u5706\u76d8\r\n * barNum\uff1a\u5706\u76d8\u4e2a\u6570\r\n * host\uff1a\u5438\u9644\u8282\u70b9\r\n * *\/\r\nfunction createBarrels(barNum, host){\r\n    \/\/ \u5706\u76d8\u521d\u59cbx\u4f4d\u7f6e\r\n    var pos = host.p3();\r\n\r\n    for(var i = barNum, j = 0; i > 0; i--, j++){\r\n        pos[1] = barrelHeight * j + floorY;\r\n        positions[0].barrels.push(createBarrel(pos, [1, barrelHeight, 1], barrelMinORadius + i*poorRadius, barrelIRadius, host).s({\r\n            'shape3d.color': randomColor(),\r\n            '3d.movable': false\r\n        }));\r\n    }\r\n}\r\n\r\n\/**\r\n * \u521b\u5efa\u8282\u70b9\r\n * p3\uff1a\u8282\u70b9\u4f4d\u7f6e\r\n * s3\uff1a\u8282\u70b9\u5927\u5c0f\r\n * host\uff1a\u5438\u9644\u8282\u70b9\r\n * *\/\r\nfunction createNode(p3, s3, host){\r\n    var node = new ht.Node();\r\n    node.p3(p3);\r\n    node.s3(s3);\r\n    node.setHost(host);\r\n    node.s({\r\n        'wf.visible': 'selected',\r\n        'wf.color': '#FF6B10',\r\n        'wf.width': 2,\r\n        'wf.short': true\r\n    });\r\n    dataModel.add(node);\r\n    return node;\r\n}\r\n\r\n\/**\r\n * \u521b\u5efa\u7a7a\u5fc3\u5706\u67f1\r\n * p3\uff1a\u5706\u6876\u4f4d\u7f6e\r\n * s3\uff1a\u5706\u6876\u5927\u5c0f\r\n * oRadius\uff1a\u5706\u6876\u5916\u5f84\r\n * iRadius\uff1a\u5706\u6876\u5185\u5f84\r\n * host\uff1a\u5438\u9644\u8282\u70b9\r\n * *\/\r\nfunction createBarrel(p3, s3, oRadius, iRadius, host){\r\n    return createNode(p3, s3, host).s({\r\n        'shape3d':  ht.Default.createRingModel([\r\n            oRadius, 1,\r\n            oRadius, 0,\r\n            iRadius, 0,\r\n            iRadius, 1,\r\n            oRadius, 1\r\n        ], null, 20, false, false, 70)\r\n    });\r\n}\r\n<\/pre>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[],"_links":{"self":[{"href":"https:\/\/www.hightopo.com\/blog\/wp-json\/wp\/v2\/posts\/391"}],"collection":[{"href":"https:\/\/www.hightopo.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.hightopo.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.hightopo.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.hightopo.com\/blog\/wp-json\/wp\/v2\/comments?post=391"}],"version-history":[{"count":1,"href":"https:\/\/www.hightopo.com\/blog\/wp-json\/wp\/v2\/posts\/391\/revisions"}],"predecessor-version":[{"id":392,"href":"https:\/\/www.hightopo.com\/blog\/wp-json\/wp\/v2\/posts\/391\/revisions\/392"}],"wp:attachment":[{"href":"https:\/\/www.hightopo.com\/blog\/wp-json\/wp\/v2\/media?parent=391"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.hightopo.com\/blog\/wp-json\/wp\/v2\/categories?post=391"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.hightopo.com\/blog\/wp-json\/wp\/v2\/tags?post=391"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}