forceAtlas2.html 5.5 KB
<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Force Atlas2 - ECHARTS-GL</title>
        <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
        <meta name="apple-mobile-web-app-capable" content="yes"> <!-- Fullscreen Landscape on iOS -->
        <link rel="stylesheet" href="./common.css">
    </head>
    <body>
        <script src="../node_modules/echarts/dist/echarts.js"></script>
        <script src="../node_modules/echarts/dist/extension/dataTool.js"></script>
        <script src="../dist/echarts-gl.js"></script>
        <script src="lib/jquery.min.js"></script>
        <script src="js/commonUI.js"></script>
        <script>
            var forceAtlas = new echarts.ForceAtlas2GPU();

            var renderer = new echarts.graphicGL.Renderer();

            function createNodes(widthCount, heightCount) {
                var nodes = [];
                for (var i = 0; i < widthCount; i++) {
                    for (var j = 0; j < heightCount; j++) {
                        nodes.push({
                            x: Math.random() * window.innerWidth,
                            y: Math.random() * window.innerHeight
                        });
                    }
                }
                return nodes;
            }

            function createEdges(widthCount, heightCount) {
                var edges = [];
                for (var i = 0; i < widthCount; i++) {
                    for (var j = 0; j < heightCount; j++) {
                        if (i < widthCount - 1) {
                            edges.push({
                                node1: i + j * widthCount,
                                node2: i + 1 + j * widthCount,
                                weight: 2
                            });
                        }
                        if (j < heightCount - 1) {
                            edges.push({
                                node1: i + j * widthCount,
                                node2: i + (j + 1) * widthCount,
                                weight: 2
                            });
                        }
                    }
                }
                return edges;
            }
            var nodes = createNodes(100, 100);
            var edges = createEdges(100, 100);
            forceAtlas.initData(nodes, edges);
            forceAtlas.updateOption({
                gravityCenter: [window.innerWidth / 2, window.innerHeight / 2],
                gravity: 4,
                scaling: 0.4,
                edgeWeightInfluence: 2
            });

            var canvas = document.createElement('canvas');
            canvas.width = window.innerWidth;
            canvas.height = window.innerHeight;
            var ctx = canvas.getContext('2d');
            document.body.appendChild(canvas);

            var debugCanvas = document.createElement('canvas');
            var debugCtx = debugCanvas.getContext('2d');
            debugCanvas.style.cssText = 'position:absolute;left:0;top:0;';
            document.body.appendChild(debugCanvas);

            function step() {
                console.time('layout');
                for (var i = 0; i < 1; i++) {
                    forceAtlas.step(renderer);
                }
                console.timeEnd('layout');

                var data = forceAtlas.getTextureData(renderer, 'position');
                var textureSize = forceAtlas.getTextureSize();
                debugCanvas.width = textureSize.width;
                debugCanvas.height = textureSize.height;
                var imageData = debugCtx.createImageData(textureSize.width, textureSize.height);
                for (var i = 0; i < data.length / 4; i++) {
                    var i4 = i * 4;
                    imageData.data[i4] = data[i4];
                    imageData.data[i4 + 1] = data[i4 + 1];
                    imageData.data[i4 + 2] = 0;
                    imageData.data[i4 + 3] = 255;
                }

                debugCtx.putImageData(imageData, 0, 0);

                drawDebug();

                setTimeout(step, 1000);
            }
            setTimeout(step, 10);

            var nodePosition = new Float32Array(nodes.length * 2);
            // Debug
            function drawDebug() {
                // console.log(forceAtlas.getTextureData(renderer, 'forcePrev'));
                forceAtlas.getNodePosition(renderer, nodePosition);
                console.time('render');
                ctx.clearRect(0, 0, canvas.width, canvas.height);
                ctx.beginPath();
                ctx.fillStyle = 'rgba(255, 255, 255, 0.7)';
                for (var i = 0; i < nodes.length; i++) {
                    var x = nodePosition[i * 2];
                    var y = nodePosition[i * 2 + 1]
                    ctx.rect(x - 2, y - 2, 4, 4);
                }
                ctx.fill();
                ctx.strokeStyle = 'rgba(255, 255, 255, 0.2)';
                ctx.lineWidth = 1;
                ctx.beginPath();
                for (var i = 0; i < edges.length; i++) {
                    var edge = edges[i];
                    var x0 = nodePosition[edge.node1 * 2];
                    var y0 = nodePosition[edge.node1 * 2 + 1];
                    var x1 = nodePosition[edge.node2 * 2];
                    var y1 = nodePosition[edge.node2 * 2 + 1];

                    ctx.moveTo(x0, y0);
                    ctx.lineTo(x1, y1);
                }
                ctx.stroke();
                console.timeEnd('render');
            }
        </script>
    </body>
</html>