Страницы

Поиск по вопросам

среда, 1 января 2020 г.

Автоматическое соединение блоков релятивными связями

#javascript #css #html5 #svg #relation


Я ищу библиотеку javascript или нестандартное решение, где я могу свободно перетаскивать
компоненты и поддерживать связь между ними. Например,  подключать один узел  к другому
и свободно перемещать узлы, куда я хочу). 

Под поддержанием отношений я подразумеваю, что различные компоненты должны поддерживать
свои релятивные взаимосвязи (как блок-схема).  

После  рисования связей мне нужно получить данные JSON об их релятивных отношениях.

Ниже приведен пример того, о чем я говорю: 

     

На рисунке выше, как вы можете видеть, у меня есть разные узлы, которые связаны между
собой. Как я могу достичь этих целей с помощью библиотеки или индивидуального решения?    

Изображение выше из библиотеки реакции strom-react-diagrmas. Я пробовал это, но он
использует SVG и не хватает много настроек, которые я хочу.   

Я также пробовал rete.js, но не смог настроить его в соответствии со своими потребностями
(настройка форм и т.д.)  

   

Я также думаю о создании решения с нуля, единственная проблема, с которой я сталкиваюсь,
состоит в том, как мне соединить два или несколько элементов div на холсте, поддерживая
их взаимосвязь?  

Обратите внимание, почему я это делаю?     


Моя цель состоит в том, - что  я хочу создать визуальный редактор, в котором не технический
специалист мог бы спроектировать поток, а затем я хочу экспортировать JSON, чтобы соответствующим
образом сохранить его в моей базе  данных.
Когда я снова загружу холст этого потока, я смогу снова
визуализировать поток взаимосвязи вместе со связанными узлами на
основе данных JSON, которые у меня будут.


Можете ли вы предложить мне что-то, если вы сталкивались с такой ситуацией?  

Любая помощь от вас, ребята, очень ценится. 
    


Ответы

Ответ 1



Вы можете использовать библиотеку GOJS. Это отличное решение для коммерческого проекта. Она гибкая в настройках и позволяет довольно легко делать удивительные вещи. Пример с официального сайта. function init() { if (window.goSamples) goSamples(); // init for these samples -- you don't need to call this var $ = go.GraphObject.make; // for conciseness in defining templates myDiagram = $(go.Diagram, "myDiagramDiv", { validCycle: go.Diagram.CycleNotDirected, // don't allow loops // For this sample, automatically show the state of the diagram's model on the page "undoManager.isEnabled": true }); // This template is a Panel that is used to represent each item in a Panel.itemArray. // The Panel is data bound to the item object. var fieldTemplate = $(go.Panel, "TableRow", // this Panel is a row in the containing Table new go.Binding("portId", "name"), // this Panel is a "port" { background: "transparent", // so this port's background can be picked by the mouse fromSpot: go.Spot.Right, // links only go from the right side to the left side toSpot: go.Spot.Left, // allow drawing links from or to this port: fromLinkable: true, toLinkable: true }, $(go.Shape, { width: 12, height: 12, column: 0, strokeWidth: 2, margin: 4, // but disallow drawing links from or to this shape: fromLinkable: false, toLinkable: false }, new go.Binding("figure", "figure"), new go.Binding("fill", "color")), $(go.TextBlock, { margin: new go.Margin(0, 5), column: 1, font: "bold 13px sans-serif", alignment: go.Spot.Left, // and disallow drawing links from or to this text: fromLinkable: false, toLinkable: false }, new go.Binding("text", "name")), $(go.TextBlock, { margin: new go.Margin(0, 5), column: 2, font: "13px sans-serif", alignment: go.Spot.Left }, new go.Binding("text", "info")) ); // This template represents a whole "record". myDiagram.nodeTemplate = $(go.Node, "Auto", { copyable: false, deletable: false }, new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify), // this rectangular shape surrounds the content of the node $(go.Shape, { fill: "#EEEEEE" }), // the content consists of a header and a list of items $(go.Panel, "Vertical", // this is the header for the whole node $(go.Panel, "Auto", { stretch: go.GraphObject.Horizontal }, // as wide as the whole node $(go.Shape, { fill: "#1570A6", stroke: null }), $(go.TextBlock, { alignment: go.Spot.Center, margin: 3, stroke: "white", textAlign: "center", font: "bold 12pt sans-serif" }, new go.Binding("text", "key"))), // this Panel holds a Panel for each item object in the itemArray; // each item Panel is defined by the itemTemplate to be a TableRow in this Table $(go.Panel, "Table", { padding: 2, minSize: new go.Size(100, 10), defaultStretch: go.GraphObject.Horizontal, itemTemplate: fieldTemplate }, new go.Binding("itemArray", "fields") ) // end Table Panel of items ) // end Vertical Panel ); // end Node myDiagram.linkTemplate = $(go.Link, { relinkableFrom: true, relinkableTo: true, // let user reconnect links toShortLength: 4, fromShortLength: 2 }, $(go.Shape, { strokeWidth: 1.5 }), $(go.Shape, { toArrow: "Standard", stroke: null }) ); myDiagram.model = $(go.GraphLinksModel, { copiesArrays: true, copiesArrayObjects: true, linkFromPortIdProperty: "fromPort", linkToPortIdProperty: "toPort", nodeDataArray: [{ key: "Record1", fields: [{ name: "field1", info: "", color: "#F7B84B", figure: "Ellipse" }, { name: "field2", info: "the second one", color: "#F25022", figure: "Ellipse" }, { name: "fieldThree", info: "3rd", color: "#00BCF2" } ], loc: "0 0" }, { key: "Record2", fields: [{ name: "fieldA", info: "", color: "#FFB900", figure: "Diamond" }, { name: "fieldB", info: "", color: "#F25022", figure: "Rectangle" }, { name: "fieldC", info: "", color: "#7FBA00", figure: "Diamond" }, { name: "fieldD", info: "fourth", color: "#00BCF2", figure: "Rectangle" } ], loc: "280 0" } ], linkDataArray: [{ from: "Record1", fromPort: "field1", to: "Record2", toPort: "fieldA" }, { from: "Record1", fromPort: "field2", to: "Record2", toPort: "fieldD" }, { from: "Record1", fromPort: "fieldThree", to: "Record2", toPort: "fieldB" } ] }); } init();


Ответ 2



Это демо, где вы можете нажать на серые точки. Когда подряд щелкают 2 точки, связь между двумя точками рисуется на холсте svg. В HTML у вас есть все ваши элементы внутри элемента #wrap. Под элементами div находится элемент svg того же размера, что и # wrap. Дивы позиционированы абсолютно с атрибутами top иleft в процентах. Svg canvas имеет viewBox = "0 0 100 100" и preserveAspectRatio = "none" для того, чтобы адаптировать рисунок к размеру # wrap Соединительные линии - это пути, нарисованные в svg с помощью fill: none и vector-effect: non-scaling-stroke; для достижения равномерной толщины линий при увеличении или уменьшении размера холста. В конце вы можете сохранить массив точек для данных. Я надеюсь, что это может дать вам представление о том, что вам нужно сделать. const SVG_NS = 'http://www.w3.org/2000/svg'; let mainBox = wrap.getBoundingClientRect(); let dots = Array.from(document.querySelectorAll(".dot")) let points = []; let count = 0; dots.forEach(d=>{ d.addEventListener("click",(e)=>{ let bcr = d.getBoundingClientRect(); mainBox = wrap.getBoundingClientRect() // расчёт x и y координат для разъемов числом от 0 до 100 let x = map(bcr.left - mainBox.left + bcr.width/2, mainBox.left, mainBox.left + mainBox.width, 0, 100); let y = map(bcr.top - mainBox.top + bcr.height/2, mainBox.top, mainBox.top + mainBox.height, 0, 100); points.push({x,y}) if(count % 2 == 1){ // соединяет последние 2 точки в массиве drawConnector(points[points.length-1],points[points.length-2]) } count++; }) }) function map(n, a, b, _a, _b) { let d = b - a; let _d = _b - _a; let u = _d / d; return _a + n * u; } function drawConnector(a,b){ let path = document.createElementNS(SVG_NS, 'path'); let d = `M${a.x},${a.y} C50,${a.y} 50 ${b.y} ${b.x} ${b.y}`; path.setAttributeNS(null,"d",d); svg.appendChild(path) } * { box-sizing: border-box; } .box { width: 20%; height: 100px; border: 1px solid #bbb; border-radius: 10px; position: absolute; background: #efefef; } #wrap { position: absolute; margin:auto; top:0;bottom:0;left:0;right:0; width: 60%; height: 350px; border: 1px solid; min-width: 350px; } svg { position: absolute; width: 100%; height: 100%; background: rgba(0, 100, 250, 0.25); } .dot { width: 20px; height: 20px; border-radius: 50%; border: 1px solid #999; background: #d9d9d9; position: relative; left: calc(100% - 10px); } .dot:hover { border-color: tomato; } path { fill: none; stroke: black; vector-effect: non-scaling-stroke; stroke-width: 1px; stroke: #555; }
Связанный ответ: Рисование изогнутых линий cо стрелками SVG от одного div к другому div Источник: @enxaneta

Комментариев нет:

Отправить комментарий