【问题标题】:Draw a circle around nodes groups在节点组周围画一个圆圈
【发布时间】:2021-04-11 11:23:42
【问题描述】:

在下面的 vis-network 中,我有 2 组节点。在生成layput_as_tree 后,通过访问节点位置,我将 2 组节点分为左侧和右侧。现在想在节点组周围画一个圆或椭圆。 这是一个可重现的例子

require(shiny)
require(visNetwork)
server <- function(input, output) {
  output$network <- visNetwork::renderVisNetwork({
    edges <- data.frame(
      from = sample(1:10, 8),
      to = sample(1:10, 8),
      label = paste("interaction type", 1:8),
      length = c(100, 500),
      width = c(4, 1),
      arrows = c("to", "from", "middle", "middle;to"),
      dashes = c(TRUE, FALSE),
      title = paste("interaction name", 1:8),
      smooth = c(FALSE, TRUE),
      shadow = c(FALSE, TRUE, FALSE, TRUE)
    )
    nodes <- data.frame(
      id = 1:10,
      group = c("A", "B"),
      label = paste("Node", 1:10),
      shape = "ellipse"
    )

    # save the graph in variable
    g <-
      visNetwork::visNetwork(nodes, edges, height = "500px", width = "100%") %>% 
      visNetwork::visIgraphLayout(layout = "layout_as_tree")

    # access the x and y co-ordinates to arrange the groups
    coords <- g$x$nodes %>%
      dplyr::mutate(x = abs(x)) %>%
      dplyr::mutate(y = abs(y)) %>%
      dplyr::mutate(x = ifelse(group %in% "A", -x, x)) %>%
      dplyr::select(x, y) %>%
      as.matrix()

    #' replot the network with the new co-ordinates
    visNetwork::visNetwork(nodes, edges, height = "500px", width = "100%") %>%
     visNetwork::visIgraphLayout(
      layout = "layout.norm",
      layoutMatrix = coords,
      randomSeed = 1,
      smooth = T
    ) 
  })
}

ui <- shiny::fluidPage(
  visNetwork::visNetworkOutput("network",
    width = "1000px", height = "700px"
  )
)

shiny::shinyApp(ui = ui, server = server)

【问题讨论】:

  • 我不太确定:您所取得的成就(最后一张图片)看起来不像您要求的那样?现在有什么问题?
  • “以编程方式使 x 和 y 更接近我的图片 2”是什么意思?一些算法?
  • 我建议你先看看这里stackoverflow.com/questions/5028433/graph-auto-layout-algorithm。然后,当您清楚您需要什么时,我会提出一个新问题。
  • 已经有不同的算法可以做到这一点 - 请参阅我的链接。为什么你还需要别的东西? “看起来不错”是什么意思?在您的案例中,与现有的算法有什么不同?
  • 这取决于您使用的是什么“画布”...如果您将网页称为“画布”,那么您可以使用 css 边框半径属性将元素转换为圆形形状。如果您使用的是 html5 canvas 标签,那就有点不同了。去死吧!你打败了我!我很高兴你明白了。我打算用随机生成的点来演示这个概念。

标签: javascript r shiny vis.js visnetwork


【解决方案1】:

我正在完成剧本,但我必须离开……会回来完成。

//The nodeGraph variable should probably be ran through a transitive
//closure algorithm to simiplify it, so its not an overly complicated
//network
nodeGraph = {};


//create nodes and the beginnings of a dictionary for a directed graph
//to later be used to adjust the positions of nodes - note this is not
//the most efficient algorithm.

nodeCount = 10;

for (var i = 0; i < nodeCount; i++)
{
  var div = document.createElement('div');
  div.id = "node" + i;
  div.className = "node";
  div.setAttribute("group", (randomInt(1, 2) == 1) ? "A" : "B")
  nodeGraph["node" + i] = [];
  document.getElementsByClassName('container')[0].append(div);
}

//here I randomly create a relationship amongst nodes - but I limit it to 5 relationships just so its not too resource heavy.

//loop through each node
for (var i = 0; i < nodeCount; i++)
{
  //generate number of relationships
  randInt = randomInt(1, 5);
  
  //generate random relationships
  for (var j = 0; j < randInt; j++)
  {
    ranNum = randomInt(0, nodeCount - 1);
    //console.log(ranNum);
    while (nodeGraph["node" + i].includes(ranNum))
    {
      ranNum = randomInt(0, nodeCount - 1);
    }
    //console.log(ranNum);
    nodeGraph["node" + i].push("node" + ranNum);
  }
}

//outputs the random relationship amongst nodes
console.log(nodeGraph);

//the above code sets up the problem for what we want to achieve
//which is to essentially sort the nodes into the two "cells"

//lets get the location of the parent cells and a reference to them
groupABox = document.getElementById('GroupA');
groupABBox = groupABox.getBoundingClientRect();
groupBBox = document.getElementById('GroupB');
groupBBBox = groupBBox.getBoundingClientRect();
//then loop through every node and stick them into their respective groups
for (var i = 0; i < nodeCount; i++)
{
  currentNode = document.getElementById("node" + i);
  group = currentNode.getAttribute('group');
  if (group == 'A')
  {
    relationships = nodeGraph['node' + i];
    for (var j = 0; j < relationships.length; j++)
    {
      comparedNode = document.getElementById(relationships[j]);
      if (comparedNode.getAttribute('group') == 'A')
      {
      }
      else
      {
      }
    }
  }
}

function randomInt(min, max)
{ 
  return Math.floor(Math.random() * (max - min + 1) + min);
}
.parentNode
{
  border-radius: 100px;
  border: solid black 5px;
  height: 500px;
  width: 200px;
  position: relative;
  background-color: lightblue;
}

#GroupA
{
  float: left;
}

#GroupB
{
  float: right;
}

.node
{
  height: 20px;
  width: 20px;
  position: absolute;
  float: none;
  background-color: green;
}
<div class="container">
  <div id="GroupA" class="parentNode">
  </div>
  <div id="GroupB" class="parentNode">
  </div>
</div>

https://jsfiddle.net/Shmac/x1wf52ba/1/

【讨论】:

  • 我解决了圆圈问题并更新了 Q。您是否介意删除旧的 cmets,因为我们的讨论是关于圆圈的,这样就不会混淆读者。谢谢
  • 是的。我想提一下,由于要在画布上绘制首先需要创建一个对象 - 特别是 context,因此无法使用纯 JavaScript 解决圆圈问题。像这样的东西应该是闪亮的。当您在创建点后尝试绘制圆时,原始上下文将替换为新创建的上下文。我也应该删除我的答案吗?不幸的是,我不认为它有用。我必须做很多工作来生成仅连接到 2 max 的节点 - 然后创建算法......
  • 当然,我不知道 VisEvents 是我们可以传递 JS 代码的地方。一旦我明白这一点,我所做的就是检查w3 schools on drawing a circle on canvas,因为 visnetwork 显示在画布上并导致解决方案。
  • 很高兴你明白了。对不起,我的回答太没用了,大声笑。
【解决方案2】:

使用 visEvents 并传递 Javascript 代码能够在节点组周围生成圆圈。

graph %>%
    visNetwork::visEvents(type = "on", beforeDrawing = "function(ctx) {
    ctx.fillStyle = 'rgba(255, 0, 255, 0.1)';
    ctx.ellipse(-180 , 25, 150, 280 , 0, 0, 2 * Math.PI);
    ctx.fill();
    ctx.fillStyle = 'rgba(64, 255, 255,0.1)';
    ctx.ellipse(180 , 25, 150, 280, 0, 0, 2 * Math.PI);
    ctx.fill();
}")

【讨论】:

    猜你喜欢
    • 2021-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-21
    相关资源
    最近更新 更多