Принудительно ориентировать граф с помощью D3.js - вход, выход, обновление по нажатию кнопки - PullRequest
0 голосов
/ 04 декабря 2018

Целью программы является отображение графиков и их раскраска в соответствии с числом n вершин.Правило раскраски:

n = 3 -> зеленый цвет

n = 5 -> красный цвет

n не равен 3 или 5 -> ничего не делать

Дополнительное правило: если имя вершины = "2", вершина должна быть желтого цвета.

Данные графика хранятся в текстовых файлах.Они расположены в той же папке, что и проект.Это два файла.

GraphN3.txt:

p edge 3 3
e 1 2
e 2 1
e 1 3
e 2 3

GraphN5.txt:

p edge 5 5
e 87 88
e 88 89
e 89 90
e 90 91
e 91 87

Первая строка в файлах не обрабатывается, но всегдаожидается. Важное замечание: в конце каждого файла есть конец строки (клавиша ввода).

D3.js используется в проекте для принудительно ориентированного графа.Вход «browseFile» позволяет мне выбрать график, который я хочу отобразить.«Выполнить раскраску» окрашивает отображаемый график в соответствии с правилами раскраски.

Проблема, которую я получаю, заключается в следующем: я получаю правильную раскраску только для первого файла графика, который я открываю.Любое продолжающееся открытие файла не приводит к окраске.

После перезагрузки браузера раскраска происходит.Я хочу иметь возможность открывать и раскрашивать графики много раз без необходимости перезагрузки браузера.HTML-код:

<!DOCTYPE html>
<meta charset="utf-8">
<head>
 <script
        src="https://code.jquery.com/jquery-3.2.1.js"
        integrity="sha256-DZAnKJ/6XZ9si04Hgrsxu/8s717jcIzLy3oi35EouyE="
        crossorigin="anonymous"></script>
  <meta charset="utf-8">
  <title>Force Directed Graph</title>
</head>
<body>
 <input type='file' id="browseFile" >
 <button  onclick="runColoring()">run coloring </button>
 <svg width="960" height="600"></svg>
 <script src="https://d3js.org/d3.v4.min.js"></script>
 <script src="graphScript.js"></script>
</body>

код 'graphScript.js':

class Graph {

    constructor()
    {
        this.vertexNeighbours = new Map();
        this.nodes_data = [];
        this.links_data = [];
    }

    createVertex(v)
    {
        var alreadyExisting = false;
        var get_keys = this.vertexNeighbours.keys();
        for (var i of get_keys)
        {
            // if true - the vertex already existed and should not be added
            if(i.toString().trim() == v.toString().trim())
            {
                alreadyExisting = true;
                break
            }
        }
        if (alreadyExisting == false)
        {
            // nodes_data update
            this.nodes_data.push({"name": v});

            //  vertex neighbours list
            this.vertexNeighbours.set(v, []);
        }
    }

    createEdge(v, w)
    {
        var alreadyExisting = false;
        var get_keys = this.vertexNeighbours.keys();
        for (var i of get_keys)
        {
            if(i.toString().trim() == v.toString().trim())
            {
                var get_values = this.vertexNeighbours.get(i);
                for (var j of get_values)
                {
                    // if true - the edge already existed and should not be added
                    if(j.toString().trim() == w.toString().trim())
                    {
                        alreadyExisting = true;
                        break
                    }
                }
            }
        }
        if (alreadyExisting == false)
        {
            this.links_data.push({"source":v,"target":w});
            this.vertexNeighbours.get(v).push(w);
            this.vertexNeighbours.get(w).push(v);
        }
    }

    colorVertices()
    {
        var VerticesColor = "";
        var get_keys = this.vertexNeighbours.keys();
        var keysQuant = 0;
        for(var i of get_keys)
        {
            keysQuant++;
        }
        if (keysQuant == 3 )
        {
            VerticesColor = "green";
        }
        if (keysQuant == 5)
        {
            VerticesColor = "red";
        }

        svg.select("g")
            .attr("class", "nodes")
            .selectAll("circle")
            .style("fill", function(d) {
                if (d.name == "2") {
                    return "yellow";
                }
                else
                    return VerticesColor;
            });
    }
}


var svg = d3.select("svg"),
    width = +svg.attr("width"),
    height = +svg.attr("height");

var gr = new Graph();
var input = document.getElementById('browseFile');


function runColoring()
{
    gr.colorVertices();
}

input.onchange= function fileOpening() {                                //myFunction na klikniecie 'Try it' uruchamia wczytywanie danych

    var filePath = document.getElementById("browseFile").files[0].name;


    $.get(filePath, function (graphData) {
            console.log(graphData);

            gr = new Graph();

            gr.nodes_data = [];
            gr.links_data = [];

            d3.selectAll("g > *").remove();


            var splittedLines = graphData.split('\n');

            var j = 0;
            while (splittedLines[j+1] != null && splittedLines[j+2] != undefined)
            {
                var  dataLines = splittedLines[j+1].split(" ");
                gr.createVertex(dataLines[1].trim());
                gr.createVertex(dataLines[2].trim());
                j++;
            }

            j = 0;
            while (splittedLines[j+1] != null && splittedLines[j+2] != undefined)
            {
                dataLines = splittedLines[j+1].split(" ");
                gr.createEdge(dataLines[1].trim(),dataLines[2].trim());
                j++;
            }

            var nodes_data =  gr.nodes_data;
            //Create links data
            var links_data = gr.links_data;

            var radius = 9;

//set up the simulation and add forces
            var simulation = d3.forceSimulation()
                .nodes(nodes_data);

            var link_force =  d3.forceLink(links_data)
                .id(function(d) { return d.name; });

            var charge_force = d3.forceManyBody()
                .strength(-100);

            var center_force = d3.forceCenter(width / 2, height / 2);

            simulation
                .force("charge_force", charge_force)
                .force("center_force", center_force)
                .force("links",link_force)
            ;


//add tick instructions:
            simulation.on("tick", tickActions );

//add encompassing group for the zoom
            var g = svg.append("g")
                .attr("class", "everything");

//draw lines for the links
            var link = g.append("g")
                .attr("class", "links")
                .selectAll("line")
                .data(links_data)
                .enter().append("line")
                .attr("stroke-width", 2)
                .style("stroke", linkColour);

//draw circles for the nodes
            var node = g.append("g")
                .attr("class", "nodes")
                .selectAll("circle")
                .data(nodes_data)
                .enter()
                .append("circle")
                .attr("r", radius);
            //  .attr("fill", circleColour);

//add drag capabilities
            var drag_handler = d3.drag()
                .on("start", drag_start)
                .on("drag", drag_drag)
                .on("end", drag_end);

            drag_handler(node);


//add zoom capabilities
            var zoom_handler = d3.zoom()
                .on("zoom", zoom_actions);

            zoom_handler(svg);

            /** Functions **/

//Function to choose the line colour
            function linkColour(d){
                    return "red";
            }

//Drag functions
//d is the node
            function drag_start(d) {
                if (!d3.event.active) simulation.alphaTarget(0.3).restart();
                d.fx = d.x;
                d.fy = d.y;
            }
//make sure you can't drag the circle outside the box
            function drag_drag(d) {
                d.fx = d3.event.x;
                d.fy = d3.event.y;
            }

            function drag_end(d) {
                if (!d3.event.active) simulation.alphaTarget(0);
                d.fx = null;
                d.fy = null;
            }
//Zoom functions
            function zoom_actions(){
                g.attr("transform", d3.event.transform)
            }

            function tickActions() {
                //update circle positions each tick of the simulation
                node
                    .attr("cx", function(d) { return d.x; })
                    .attr("cy", function(d) { return d.y; });

                //update link positions
                link
                    .attr("x1", function(d) { return d.source.x; })
                    .attr("y1", function(d) { return d.source.y; })
                    .attr("x2", function(d) { return d.target.x; })
                    .attr("y2", function(d) { return d.target.y; });
            }

        }
    )
};
...