{"id":804,"date":"2022-10-26T11:38:03","date_gmt":"2022-10-26T11:38:03","guid":{"rendered":"https:\/\/alphagrowth.es\/?page_id=804"},"modified":"2022-10-27T08:08:08","modified_gmt":"2022-10-27T08:08:08","slug":"defi-track","status":"publish","type":"page","link":"https:\/\/alphagrowth.es\/es\/defi-track\/","title":{"rendered":"DeFi Track"},"content":{"rendered":"<script src=\"\/\/unpkg.com\/three\"><\/script>\n<script src=\"\/\/unpkg.com\/3d-force-graph\"><\/script>\n<div class=\"relative\">\n    <div id=\"ag-graph\" class=\"px-5 md:px-3\"><\/div>\n    <button id=\"btn-reset-ag-graph\" class=\"bg-red px-5 py-2 rounded-md absolute top-3 right-4\">Reset<\/button>\n<\/div>\n\n<script defer>\n    \/\/#region CSS2DRenderer\n    (function() {\n\n        class CSS2DObject extends THREE.Object3D {\n\n            constructor(element = document.createElement('div')) {\n\n                super();\n                this.isCSS2DObject = true;\n                this.element = element;\n                this.element.style.position = 'absolute';\n                this.element.style.userSelect = 'none';\n                this.element.setAttribute('draggable', false);\n                this.addEventListener('removed', function() {\n\n                    this.traverse(function(object) {\n\n                        if (object.element instanceof Element && object.element.parentNode !== null) {\n\n                            object.element.parentNode.removeChild(object.element);\n\n                        }\n\n                    });\n\n                });\n\n            }\n            copy(source, recursive) {\n\n                super.copy(source, recursive);\n                this.element = source.element.cloneNode(true);\n                return this;\n\n            }\n\n        }\n\n        \/\/\n\n        const _vector = new THREE.Vector3();\n        const _viewMatrix = new THREE.Matrix4();\n        const _viewProjectionMatrix = new THREE.Matrix4();\n        const _a = new THREE.Vector3();\n        const _b = new THREE.Vector3();\n        class CSS2DRenderer {\n\n            constructor(parameters = {}) {\n\n                const _this = this;\n                let _width, _height;\n                let _widthHalf, _heightHalf;\n                const cache = {\n                    objects: new WeakMap()\n                };\n                const domElement = parameters.element !== undefined ? parameters.element : document.createElement('div');\n                domElement.style.overflow = 'hidden';\n                this.domElement = domElement;\n                this.getSize = function() {\n\n                    return {\n                        width: _width,\n                        height: _height\n                    };\n\n                };\n\n                this.render = function(scene, camera) {\n\n                    if (scene.matrixWorldAutoUpdate === true) scene.updateMatrixWorld();\n                    if (camera.parent === null && camera.matrixWorldAutoUpdate === true) camera.updateMatrixWorld();\n                    _viewMatrix.copy(camera.matrixWorldInverse);\n                    _viewProjectionMatrix.multiplyMatrices(camera.projectionMatrix, _viewMatrix);\n                    renderObject(scene, scene, camera);\n                    zOrder(scene);\n\n                };\n\n                this.setSize = function(width, height) {\n\n                    _width = width;\n                    _height = height;\n                    _widthHalf = _width \/ 2;\n                    _heightHalf = _height \/ 2;\n                    domElement.style.width = width + 'px';\n                    domElement.style.height = height + 'px';\n\n                };\n\n                function renderObject(object, scene, camera) {\n\n                    if (object.isCSS2DObject) {\n\n                        _vector.setFromMatrixPosition(object.matrixWorld);\n                        _vector.applyMatrix4(_viewProjectionMatrix);\n                        const visible = object.visible === true && _vector.z >= -1 && _vector.z <= 1; \/\/ &#038;&#038; object.layers.test( camera.layers ) === true\n                        object.element.style.display = visible === true ? '' : 'none';\n                        if (visible === true) {\n\n                            object.onBeforeRender(_this, scene, camera);\n                            const element = object.element;\n                            element.style.transform = 'translate(-50%,-50%) translate(' + (_vector.x * _widthHalf + _widthHalf) + 'px,' + (-_vector.y * _heightHalf + _heightHalf) + 'px)';\n                            if (element.parentNode !== domElement) {\n\n                                domElement.appendChild(element);\n\n                            }\n\n                            object.onAfterRender(_this, scene, camera);\n\n                        }\n\n                        const objectData = {\n                            distanceToCameraSquared: getDistanceToSquared(camera, object)\n                        };\n                        cache.objects.set(object, objectData);\n\n                    }\n\n                    for (let i = 0, l = object.children.length; i < l; i++) {\n\n                        renderObject(object.children[i], scene, camera);\n\n                    }\n\n                }\n\n                function getDistanceToSquared(object1, object2) {\n\n                    _a.setFromMatrixPosition(object1.matrixWorld);\n                    _b.setFromMatrixPosition(object2.matrixWorld);\n                    return _a.distanceToSquared(_b);\n\n                }\n\n                function filterAndFlatten(scene) {\n\n                    const result = [];\n                    scene.traverse(function(object) {\n\n                        if (object.isCSS2DObject) result.push(object);\n\n                    });\n                    return result;\n\n                }\n\n                function zOrder(scene) {\n\n                    const sorted = filterAndFlatten(scene).sort(function(a, b) {\n\n                        if (a.renderOrder !== b.renderOrder) {\n\n                            return b.renderOrder - a.renderOrder;\n\n                        }\n\n                        const distanceA = cache.objects.get(a).distanceToCameraSquared;\n                        const distanceB = cache.objects.get(b).distanceToCameraSquared;\n                        return distanceA - distanceB;\n\n                    });\n                    const zMax = sorted.length;\n                    for (let i = 0, l = sorted.length; i < l; i++) {\n\n                        sorted[i].element.style.zIndex = zMax - i;\n\n                    }\n\n                }\n\n            }\n\n        }\n\n        THREE.CSS2DObject = CSS2DObject;\n        THREE.CSS2DRenderer = CSS2DRenderer;\n\n    })();\n    \/\/#endregion\n\n    function createPathStrings(filename) {\n        const basePath = `https:\/\/raw.githubusercontent.com\/codypearce\/some-skyboxes\/master\/skyboxes\/${filename}\/`;\n        const baseFilename = basePath + filename;\n        const fileType = filename == 'purplenebula' ? '.png' : '.jpg';\n        const sides = ['ft', 'bk', 'up', 'dn', 'rt', 'lf'];\n        const pathStings = sides.map(side => {\n            return baseFilename + '_' + side + fileType;\n        });\n\n        return pathStings;\n    }\n\n    function createMaterialArray(filename) {\n        const skyboxImagepaths = createPathStrings(filename);\n        const materialArray = skyboxImagepaths.map(image => {\n            let texture = new THREE.TextureLoader().load(image);\n\n            return new THREE.MeshBasicMaterial({\n                map: texture,\n                side: THREE.BackSide\n            });\n        });\n        return materialArray;\n    }\n\n    \/**\n     * Clamp de un n\u00famero\n     *\/\n    function clamp(num, min, max) {\n        return Math.min(Math.max(num, min), max);\n    }\n\n    \/**\n     * Obtner el breakpoint actual de la pantalla;\n     * Solo se tiene en cuenta 3: Phone, tablet y desktop;\n     *\/\n    function getScreenBreakpoint() {\n        let ret = 'sm';\n        const windowWidth = window.innerWidth;\n        if (windowWidth >= 768 && windowWidth < 1024) {\n            ret = 'md'\n        } else if (windowWidth >= 1024) {\n            ret = 'lg';\n        }\n        return ret;\n    }\n\n    window.onload = function() {\n        const el = document.getElementById('ag-graph')\n        const gData = window.agGraphData;\n        const nodeRelSize = 1;\n        const logoBaseSize = 75;\n\n        const Graph = ForceGraph3D({\n            extraRenderers: [new THREE.CSS2DRenderer()]\n        });\n\n        function getElementWidth() {\n            const element = document.getElementById('ag-graph')\n            const style = element.currentStyle || window.getComputedStyle(element),\n                width = element.offsetWidth, \/\/ or use style.width\n                margin = parseFloat(style.marginLeft) + parseFloat(style.marginRight),\n                padding = parseFloat(style.paddingLeft) + parseFloat(style.paddingRight),\n                border = parseFloat(style.borderLeftWidth) + parseFloat(style.borderRightWidth);\n\n            const ret = width + margin - padding + border;\n            return ret;\n        }\n        \/\/ Hacer zoom al nodo;\n        function onNodeClick(node) {\n            \/\/ Aim at node from outside it\n            const distance = 40;\n            const distRatio = 1 + distance \/ Math.hypot(node.x, node.y, node.z);\n\n            const newPos = node.x || node.y || node.z ?\n                {\n                    x: node.x * distRatio,\n                    y: node.y * distRatio,\n                    z: node.z * distRatio\n                } :\n                {\n                    x: 0,\n                    y: 0,\n                    z: distance\n                }; \/\/ special case if node is in (0,0,0)\n\n            Graph.cameraPosition(\n                newPos, \/\/ new position\n                node, \/\/ lookAt ({ x, y, z })\n                3000 \/\/ ms transition duration\n            );\n        }\n\n        function hideCards() {\n            const cards = document.getElementsByClassName(\"ag-graph-card\");\n            for (let i = 0; i < cards.length; i++) {\n                const card = cards[i];\n                if (!card.classList.contains('hidden')) {\n                    card.classList.add('hidden');\n                }\n            }\n        }\n\n        Graph(el)\n            .nodeColor('color')\n            .nodeRelSize(nodeRelSize)\n            .nodeOpacity(1)\n            .nodeResolution(20)\n            .linkDirectionalParticles(4)\n            .linkCurvature(() => 0.45)\n            .linkDirectionalParticleColor(() => '#e04c36')\n            .linkDirectionalParticleResolution(10)\n            .linkDirectionalParticleWidth(1)\n            .linkDirectionalParticleSpeed(0.005)\n            .nodeAutoColorBy('group')\n            .nodeLabel('')\n            .onNodeClick(onNodeClick)\n            .width(getElementWidth())\n            .nodeThreeObject((node) => {\n                const nodeEl = document.createElement('div');\n                nodeEl.className = 'flex flex-col items-center justify-center cursor-pointer'\n\n                let nameEl;\n                if (node.isBlockchain) {\n                    nameEl = document.createElement('p');\n                    nameEl.className = 'bg-red opacity-90 text-white rounded-md py-1 px-3 mt-2 stroke-white';\n                    nameEl.textContent = node.name;\n                }\n\n\n\n                const maxNodeValue = 250;\n                const logoEl = document.createElement('img');\n                logoEl.src = node.logo;\n                logoEl.className = 'cursor-pointer';\n                let logoSize = logoBaseSize * node.val \/ maxNodeValue;\n                logoSize = clamp(logoSize, 30, 150); \/\/ Para que no se nos vaya de madre los tama\u00f1os de las imagenes;\n                if (node.isMain) {\n                    logSize = 250;\n                }\n\n                logoEl.width = logoSize;\n                logoEl.height = logoSize;\n\n                const infoCardEl = document.createElement('div');\n                infoCardEl.className = 'ag-graph-card hidden absolute bg-black rounded-md p-4';\n                if (node.info) {\n                    \/\/ Btn de cerrar; \n                    const infoCardElBtnCloseWrapper = document.createElement('div');\n                    infoCardElBtnCloseWrapper.className = 'flex w-full flex-row-reverse justify-between items-center pb-5';\n                    const infoCardElBtnClose = document.createElement('button');\n                    infoCardElBtnClose.className = 'px-2 py-1 rounded-md';\n                    infoCardElBtnClose.innerHTML = 'X';\n                    infoCardElBtnClose.addEventListener('click', function(e) {\n                        hideCards();\n                        Graph.refresh();\n                    })\n                    infoCardElBtnCloseWrapper.append(infoCardElBtnClose);\n                    infoCardEl.append(infoCardElBtnCloseWrapper);\n\n\n                    \/\/ Nombre\n                    const infoCardElName = document.createElement('p')\n                    infoCardElName.className = 'text-red text-3xl whitespace-nowrap mb-0';\n                    infoCardElName.textContent = node.info.title;\n                    infoCardElBtnCloseWrapper.append(infoCardElName);\n\n                    \/\/ Contenido\n                    const infoCardElContent = document.createElement('div');\n                    infoCardElContent.className = 'whitespace-nowrap';\n                    infoCardElContent.innerHTML = node.info.content;\n                    infoCardEl.append(infoCardElContent);\n                }\n\n                \/\/ Append html;\n                nodeEl.append(logoEl);\n                if (nameEl) nodeEl.append(nameEl);\n                nodeEl.append(infoCardEl)\n\n                nodeEl.style.pointerEvents = 'auto';\n                nodeEl.addEventListener('click', function() {\n                    onNodeClick(node); \/\/ Hacer zoooooom; \n\n                    \/\/ Ocular otras cards;\n                    hideCards();\n                    if (node.info) {\n                        infoCardEl.classList.remove('hidden');\n                        if (getScreenBreakpoint() == 'lg') {\n                            \/\/ En desktop lo mostramos a la derecha\n                            infoCardEl.style.right = `${logoEl.width * 3}px`\n                        } else {\n                            infoCardEl.style.bottom = `${logoEl.height + 75}px`; \/\/ `px`\n                        }\n                    }\n                });\n\n                return new THREE.CSS2DObject(nodeEl);\n            })\n            \/\/ .nodeThreeObjectExtend(true)\n            .graphData(gData);\n\n\n        const BOX_DIMENSION = 2000;\n\n        const scene = Graph.scene();\n        const materialArray = createMaterialArray('purplenebula');\n        const skyboxGeo = new THREE.BoxGeometry(BOX_DIMENSION, BOX_DIMENSION, BOX_DIMENSION);\n        const skybox = new THREE.Mesh(skyboxGeo, materialArray);\n        scene.add(skybox);\n\n        const cameraControls = Graph.controls();\n        cameraControls.maxDistance = BOX_DIMENSION - 500;\n        cameraControls.update();\n\n\n\n        \/\/ Link force: Distancia entre nodos;\n        const linkForce = Graph.d3Force('link').distance(link => {\n            const {\n                source,\n                target\n            } = link;\n            \/\/ Si el source i el target estan en el mismo group la distancia es menor; \n            return source.group == target.group ? 75 : 150; \/\/ TO DO: Aqui tener en cuenta si el tama\u00f1o de la pantalla;\n        });\n\n        const initialPosition = Graph.cameraPosition();\n        document.getElementById('btn-reset-ag-graph').addEventListener('click', function() {\n            Graph.refresh();\n            Graph.cameraPosition(initialPosition)\n        });\n\n        \/\/ Responsive\n        window.onresize = function() {\n            Graph.width(getElementWidth());\n        }\n    }\n<\/script>","protected":false},"excerpt":{"rendered":"","protected":false},"author":5,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"template-graph.php","meta":[],"acf":[],"_links":{"self":[{"href":"https:\/\/alphagrowth.es\/es\/wp-json\/wp\/v2\/pages\/804"}],"collection":[{"href":"https:\/\/alphagrowth.es\/es\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/alphagrowth.es\/es\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/alphagrowth.es\/es\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/alphagrowth.es\/es\/wp-json\/wp\/v2\/comments?post=804"}],"version-history":[{"count":9,"href":"https:\/\/alphagrowth.es\/es\/wp-json\/wp\/v2\/pages\/804\/revisions"}],"predecessor-version":[{"id":839,"href":"https:\/\/alphagrowth.es\/es\/wp-json\/wp\/v2\/pages\/804\/revisions\/839"}],"wp:attachment":[{"href":"https:\/\/alphagrowth.es\/es\/wp-json\/wp\/v2\/media?parent=804"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}