mortislav_seriy
@mortislav_seriy
Веб-программист

Почему vis.js не выводит соединения, добавленные динамически через редактор?

Делаю редактор локаций на основе vis.js и столкнулся с проблемой:
Соединения, добавленные динамически (а это мне, собственно, и нужно) нормально отображаются при рендере, но при экспорте их, как будто и нет. Помогите, пожалуйста, гуру...
<!DOCTYPE html>
<html>
<head>
<meta charset="windows-1251"/>  
<meta name="viewport" content="width=device-width, initial-scale=1">

  
<style>
#graph {
  width: 100%;
  height: 60vh;
  border: 1px solid lightgray;
}

#positions {
  width: 100%;
  min-height: 32vh;
  height: 100%;
}

table.legend_table {
      font-size: 11px;
      border-width:1px;
      border-color:#d3d3d3;
      border-style:solid;
    }
    table.legend_table,td {
      border-width:1px;
      border-color:#d3d3d3;
      border-style:solid;
      padding: 2px;
    }
    div.table_content {
      width:80px;
      text-align:center;
    }
    div.table_description {
      width:100px;
    }

    #operation {
      font-size:28px;
    }
    #network-popUp {
      display:none;
      position:absolute;
      top:350px;
      left:170px;
      z-index:299;
      width:250px;
      height:120px;
      background-color: #f9f9f9;
      border-style:solid;
      border-width:3px;
      border-color: #5394ed;
      padding:10px;
      text-align: center;
    }
	
</style>
</head>
<body>
<script type="text/javascript" src="https://unpkg.com/vis@4.21.0-EOL/dist/vis.js"></script>
<link href="https://unpkg.com/vis@4.21.0-EOL/dist/vis.css" rel="stylesheet" type="text/css" />
<div id="network-popUp">
	  <span id="operation">Узел</span> <br>
	  <table style="margin:auto;"><tr>
		<td>ID</td><td><input id="node-id" value="new value" /></td>
	  </tr>
		<tr>
		  <td>Название</td><td><input id="node-label" value="new value" /></td>
		</tr></table>
	  <input type="button" value="Сохранить" id="saveButton" />
	  <input type="button" value="Отмена" id="cancelButton" />
	  
	</div>
	<br />
	
<div id="graph"></div>
<div style="width:100%; text-align: center;">
<button style="display: inline-block;" id="generate-graph">Сгенерировать карту</button>
<button style="display: inline-block;" id="extract-positions" onclick="exportNetwork()">Экспорт карты</button>
<button style="display: inline-block;" id="load-positions" onclick="importNetwork()">Импорт карты</button>
</div>
<textarea id="positions"></textarea>
<script id="code">

var importButton;
var exportButton;
var nodes = []
var edges = []
importButton = document.getElementById('load-positions');
exportButton = document.getElementById('extract-positions');
const exportArea = document.getElementById('positions')
const container = document.getElementById('graph')

function resizeExportArea() {
    exportArea.style.height = (1 + exportArea.scrollHeight) + "px";
}


const data = {
    nodes: new vis.DataSet(nodes),
    edges: new vis.DataSet(edges),
}
const options = {
    locale: 'ru',
    layout: {
        improvedLayout: false,
    },
    "edges": {
        "arrows": {
            "to": {
                "enabled": true
            },
            "from": {
                "enabled": false
            }
        },
        "dashes": false,
        "shadow": {
            "enabled": false
        },
    },
    "interaction": {
        "multiselect": true,
        "navigationButtons": true
    },
    physics: {
        barnesHut: {

            gravitationalConstant: 0,
            centralGravity: 0,
            springLength: 0,
            springConstant: 0,
            damping: 0
        },
        repulsion: {
            centralGravity: 0,
            springLength: 0,
            springConstant: 0,
            nodeDistance: 0,
            damping: 0
        },
        hierarchicalRepulsion: {
            centralGravity: 0,
            springLength: 0,
            springConstant: 0,
            nodeDistance: 0,
            damping: 0
        }
    },
    "nodes": {
        "borderWidth": 0,
        "borderWidthSelected": 0,
        "color": {
            "highlight": {},
            "hover": {}
        },
        "shape": "box",
        "shapeProperties": {
            "borderRadius": 2
        },

    },
    manipulation: {
        addNode: function(data, callback) {
            // filling in the popup DOM elements
            document.getElementById('operation').innerHTML = "Добавить локацию";
            document.getElementById('node-id').value = data.id;
            document.getElementById('node-label').value = data.label;
            document.getElementById('saveButton').onclick = saveData.bind(this, data, callback);
            document.getElementById('cancelButton').onclick = clearPopUp.bind();
            document.getElementById('network-popUp').style.display = 'block';
        },
        editNode: function(data, callback) {
            // filling in the popup DOM elements
            document.getElementById('operation').innerHTML = "Редактировать локацию";
            document.getElementById('node-id').value = data.id;
            document.getElementById('node-label').value = data.label;
            document.getElementById('saveButton').onclick = saveData.bind(this, data, callback);
            document.getElementById('cancelButton').onclick = cancelEdit.bind(this, callback);
            document.getElementById('network-popUp').style.display = 'block';
        },
        addEdge: function(data, callback) {
            if (data.from == data.to) {
                var r = confirm("Do you want to connect the node to itself?");
                if (r == true) {
                    callback(data);
                }
            } else {
                callback(data);

            }
        }
    }
}


let network = null

function clearPopUp() {
    document.getElementById('saveButton').onclick = null;
    document.getElementById('cancelButton').onclick = null;
    document.getElementById('network-popUp').style.display = 'none';
}

function cancelEdit(callback) {
    clearPopUp();
    callback(null);
}

function saveData(data, callback) {
    data.id = document.getElementById('node-id').value;
    data.label = document.getElementById('node-label').value;
    clearPopUp();	
    callback(data);
}

function initGraph() {
    network = new vis.Network(container, data, options)
}

function getNodeData(data) {
    var networkNodes = [];

    data.forEach(function(elem, index, array) {
        networkNodes.push({
            id: elem.id,
			label: elem.label,
            x: elem.x,
            y: elem.y,
			connections: elem.connections
        });
        //console.log(networkNodes);
    });
    //
    return new vis.DataSet(networkNodes);
}


function getNodeById(data, id) {
    for (var n = 0; n < data.length; n++) {
        if (data[n].id == id) { // double equals since id can be numeric or string
            return data[n];
        }
    };

    throw 'Не найден id \'' + id + '\' в данных';
}

function getEdgeData(data) {
    var networkEdges = [];

    data.forEach(function(node) {
        // add the connection
        node.connections.forEach(function(connId, cIndex, conns) {
            networkEdges.push({
                from: node.id,
                to: connId
            });
            let cNode = getNodeById(data, connId);

            var elementConnections = cNode.connections;

        });
    });

    return new vis.DataSet(networkEdges);
}

function objectToArray(obj) {
    return Object.keys(obj).map(function(key) {
        obj[key].id = key;
        return obj[key];
    });
}

function addConnections(elem, index) {   
    elem.connections = network.getConnectedNodes(index);
	console.log(elem.connections)
}

function clearOutputArea() {
    exportArea.value = "";
}

function extend(first, second) {
    for (var secondProp in second) {
        var secondVal = second[secondProp];
        if (secondVal && Object.prototype.toString.call(secondVal) === "[object Object]") {
            first[secondProp] = first[secondProp] || {};
            extend(first[secondProp], secondVal);
        } else {
            first[secondProp] = secondVal;
        }
    }
    return first;
};

function exportNetwork() {
    clearOutputArea();
    var nodes = objectToArray(network.getPositions());
    
	nodes.forEach(addConnections);
	
    var nodeslabels = data.nodes.map(({
        label
    }) => ({
        label
    }))	
	
    var exportValue = JSON.stringify(extend(nodeslabels, nodes), null, 2)
    exportArea.value = exportValue;
    resizeExportArea();
}

function importNetwork() {
    var inputValue = exportArea.value;
    var inputData = JSON.parse(inputValue);

    var data = {
        nodes: getNodeData(inputData),
        edges: getEdgeData(inputData)
    }   
	network = new vis.Network(container, data, options)
    resizeExportArea();
}


document.getElementById('generate-graph').addEventListener('click', initGraph)

</script>
</body>
</html>


Для наглядности скриншот (стрелками пометил места, где должны быть данные, но их нет)
6003bac91b6ca326098388.png

Должно работать вот так (Это я вручную в JSON прописал связи и импортировал):
6003c0f401e8e596003577.png
  • Вопрос задан
  • 252 просмотра
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы