【问题标题】:update html element with from json data使用来自 json 数据的更新 html 元素
【发布时间】:2021-03-04 13:11:21
【问题描述】:

我创建了一个 D3v6 图,我想在其中更改节点之间的关系。我为链接添加了一个上下文菜单,并填充了另一个 JSON 作为选择的选项。我遇到了两个问题:

  1. 编辑菜单没有显示正确的关系,我想我需要解析或比较这些值。
  2. 关系的更改不会更新,而是删除现有值,并且 console.log 返回“select-one”。这也坚持一个解析错误。

所以基本上我要做的是,比较来自两个 JSON 的特定值并将它们返回到 HTML 选择,该选择从这些 JSON 之一中获得填充选项。

感谢任何帮助链接或提示。

<!DOCTYPE html>
<html>

<head>
  <!-- charset -->
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>D3v6 v0.2.1</title>
  <!-- favcon -->
  <link rel="icon" href="https://networkrepository.com/favicon.png">
  <!-- call external d3.js framework -->
  <script src="https://d3js.org/d3.v6.js"></script>
  <!-- import multiselection framework -->
  <script src="https://d3js.org/d3-selection-multi.v1.js"></script>
  <!-- import "font awesome" stylesheet https://fontawesome.com/ -->
  <script src="https://kit.fontawesome.com/39094309d6.js" crossorigin="anonymous"></script>
</head>

<style>
  body {
    overflow: hidden;
    margin: 0px;
  }
  
  .canvas {
    background-color: rgb(220, 220, 220);
  }
  
  .link {
    cursor: pointer;
    stroke: rgb(0, 0, 0);
    display: none;
    stroke-width: 3px;
    opacity: 30%;
  }
  
  .link:hover {
    opacity: 100%;
  }
  
  .linkPath {
    pointer-events: none;
    display: none;
  }
  
  .node {
    stroke: white;
    stroke-width: 2px;
    cursor: pointer;
  }
  
  .icon {
    pointer-events: none;
  }
  
  #context-menu-link {
    font-family: "Open Sans", sans-serif;
    position: fixed;
    z-index: 10000;
    width: 190px;
    background: whitesmoke;
    border: 2px;
    border-radius: 6px;
    border-color: white;
    border-style: solid;
    transform: scale(0);
    transform-origin: top left;
  }
  
  #context-menu-link.active {
    transform: scale(1);
    transition: transform 200ms ease-in-out;
  }
  
  #context-menu-link .item {
    padding: 8px 10px;
    font-size: 15px;
    color: black;
  }
  
  #context-menu-link .item i {
    display: inline-block;
    margin-right: 5px;
  }
  
  #context-menu-link hr {
    margin: 5px 0px;
    border-color: whitesmoke;
  }
  
  #context-menu-link .item:hover {
    background: lightblue;
  }
  
  #details-link {
    font-family: "Open Sans", sans-serif;
    box-Shadow: 0px 0px 10px #888888;
    position: absolute;
    z-index: 10000;
    width: 300px;
    height: 150px;
    background: whitesmoke;
    border: 2px;
    border-radius: 6px;
    border-color: white;
    border-style: solid;
    transform: scale(0);
    transform-origin: top left;
  }
  
  #details-link-h3 {
    padding-left: 60px;
    margin: 10 10 10 10;
    cursor: move;
  }
  
  #details-link-text {
    padding-left: 50px;
    margin: 10 10 10 10;
  }
  
  #details-link-draggable {
    cursor: move;
  }
  
  #details-link.active {
    transform: scale(1);
    transition: transform 200ms ease-in-out;
  }
</style>

<body>

  <!-- right click context menu link-->
  <div id="context-menu-link">
    <div id="context-menu-link-details" class="item">
      <i class="fa fa-edit"></i> Relationship-Details
    </div>
  </div>

  <!-- editWindow to change link data-->
  <div id="details-link">
    <div id="details-link-draggable">
      <h3 class="fa fa-edit" id="details-link-h3"> Relationship-Details</h3>
    </div>
    <hr>
    <div id="details-link-text" class="item">
      <label id="details-link-source">Source --- </label>
      <select id="details-link-type-selection" class="item"></select>
      <label id="details-link-target"> --- Target</label>
    </div>

    <input type="button" id="confirmLinkButton" value="OK"></button>
    <input type="button" id="abortLinkButton" value="Cancel"></button>
  </div>

  <!-- create svg root element as a canvas -->
  <svg id="svg"></svg>

  <!-- call script where the magic is written -->
  <script>
    var graph = {
      "nodes": [{
          "id": 1,
          "name": "House",
          "icon": "\uf1ad",
        },
        {
          "id": 2,
          "name": "Cube",
          "icon": "\uf7b1",
        },
        {
          "id": 3,
          "name": "Rack",
          "icon": "\uf233",
        },

      ],
      "links": [{
          "source": 1,
          "target": 2,
          "type": "using"
        },
        {
          "source": 2,
          "target": 3,
          "type": "need"
        },
        {
          "source": 3,
          "target": 1,
          "type": "using"
        },
      ]
    }

    var linkTypes = {
      "1": "using",
      "2": "need"
    }

    // declare initial variables
    var svg = d3.select("svg")
    width = window.innerWidth
    height = window.innerHeight

    // define cavnas area to draw everything
    svg = d3.select("svg")
      .attr("class", "canvas")
      .attr("width", width)
      .attr("height", height)
      .call(d3.zoom().on("zoom", function(event) {
        svg.attr("transform", event.transform)
      }))
      .append("g")

    // remove zoom on dblclick listener
    d3.select("svg").on("dblclick.zoom", null)

    // append markers to svg
    svg.append('defs').append('marker')
      .attrs({
        'id': 'arrowhead',
        'viewBox': '-0 -5 10 10',
        'refX': 6,
        'refY': 0,
        'orient': 'auto',
        'markerWidth': 30,
        'markerHeight': 30,
        'xoverflow': 'visible'
      })
      .append('svg:path')
      .attr('d', 'M 0,-1 L 2 ,0 L 0,1')
      .attr('fill', 'black')
      .style('stroke', 'none');

    var linksContainer = svg.append("g").attr("class", "linksContainer")
    var nodesContainer = svg.append("g").attr("class", "nodesContainer")

    // iniital force simulation
    var simulation = d3.forceSimulation()
      .force("link", d3.forceLink().id(function(d) {
        return d.id;
      }).distance(200))
      .force("charge", d3.forceManyBody().strength(-650))
      .force("center", d3.forceCenter(width / 2, height / 2))
      .force("collision", d3.forceCollide().radius(50))

    link = linksContainer.selectAll(".link")
      .data(graph.links)
      .enter()
      .append("line")
      .attr("class", "link")
      .attr('marker-end', 'url(#arrowhead)')
      .style("display", "block")
      .on("contextmenu", contextMenuLink)

    linkPaths = linksContainer.selectAll(".linkPath")
      .data(graph.links)
      .enter()
      .append('path')
      .style("pointer-events", "none")
      .attrs({
        'class': 'linkPath',
        'fill-opacity': 1,
        'stroke-opacity': 1,
        'id': function(d, i) {
          return 'linkPath' + i
        }
      })
      .style("display", "block")

    linkLabels = linksContainer.selectAll(".linkLabel")
      .data(graph.links)
      .enter()
      .append('text')
      .style("pointer-events", "none")
      .attrs({
        'class': 'linkLabel',
        'id': function(d, i) {
          return 'linkLabel' + i
        },
        'font-size': 16,
        'fill': 'black'
      })
      .style("display", "block")

    linkLabels.append('textPath')
      .attr('xlink:href', function(d, i) {
        return '#linkPath' + i
      })
      .style("text-anchor", "middle")
      .style("pointer-events", "none")
      .attr("startOffset", "50%")
      .text(function(d) {
        return d.type
      })

    node = nodesContainer.selectAll(".node")
      .data(graph.nodes, d => d.id)
      .enter()
      .append("g")
      .attr("class", "node")
      .call(d3.drag()
        .on("start", dragStarted)
        .on("drag", dragged)
        .on("end", dragEnded)
      )

    node.append("circle")
      .attr("r", 40)
      .style("fill", "whitesmoke")

    node.append("text")
      .style("class", "icon")
      .attr("font-family", "FontAwesome")
      .attr("dominant-baseline", "central")
      .attr("text-anchor", "middle")
      .attr("font-size", 40)
      .attr("fill", "black")
      .attr("stroke-width", "0px")
      .attr("pointer-events", "none")
      .text(function(d) {
        return d.icon
      })

    simulation
      .nodes(graph.nodes)
      .on("tick", ticked);

    simulation
      .force("link")
      .links(graph.links)

    populateSelection()

    function populateSelection() {
      var fillTypeSelection = ""

      for (var key in linkTypes) {
        fillTypeSelection += "<option value=" + key + ">" + linkTypes[key] + "</option>"
      }

      document.getElementById("details-link-type-selection").innerHTML = fillTypeSelection;
    }


    function contextMenuLink(event, d) {
      thisElement = d

      event.preventDefault()

      document.getElementById("context-menu-link").classList.remove("active")

      var contextMenuLink = document.getElementById("context-menu-link")
      contextMenuLink.style.top = event.clientY + "px"
      contextMenuLink.style.left = event.clientX + "px"
      contextMenuLink.classList.add("active")

      window.addEventListener("click", function() {
        contextMenuLink.classList.remove("active")
      })

      document.getElementById("context-menu-link-details").addEventListener("click", detailsLinkClicked)
    }


    function detailsLinkClicked() {
      detailsLink(thisElement)
    }

    function detailsLink(d) {
      var editLink = document.getElementById("details-link")
      editLink.style.left = (window.innerWidth / 2) - 150 + "px"
      editLink.style.top = (window.innerHeight / 2) - 75 + "px"
      editLink.classList.add("active")

      document.getElementById("details-link-source").innerHTML = d.source.name + " --- "
      document.getElementById("details-link-target").innerHTML = " --- " + d.target.name
      document.getElementById("details-link-type-selection").type = d.type

      document.getElementById("confirmLinkButton").addEventListener("click", confirmLinkDetailsClicked)
      document.getElementById("abortLinkButton").addEventListener("click", closeLinkDetailsMenu)
    }

    function confirmLinkDetailsClicked() {
      confirmLinkDetails(thisElement)
    }

    function confirmLinkDetails(d) {
      d.type = document.getElementById("details-link-type-selection").type

      document.getElementById("details-link").classList.remove("active")
    }

    function closeLinkDetailsMenu() {
      document.getElementById("details-link").classList.remove("active")
    }


    function ticked() {
      // 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;
        });

      // update node positions
      node
        .attr("transform", function(d) {
          return "translate(" + d.x + ", " + d.y + ")";
        });

      linkPaths.attr('d', function(d) {
        return 'M ' + d.source.x + ' ' + d.source.y + ' L ' + d.target.x + ' ' + d.target.y;
      });

      linkLabels.attr('transform', function(d) {
        if (d.target.x < d.source.x) {
          var bbox = this.getBBox();

          rx = bbox.x + bbox.width / 2;
          ry = bbox.y + bbox.height / 2;
          return 'rotate(180 ' + rx + ' ' + ry + ')';
        } else {
          return 'rotate(0)';
        }
      });

    }

    function dragStarted(event, d) {
      if (!event.active) simulation.alphaTarget(0.3).restart();
      d.fx = d.x;
      d.fy = d.y;
    }

    function dragged(event, d) {
      d.fx = event.x;
      d.fy = event.y;
    }

    function dragEnded(event, d) {
      if (!event.active) simulation.alphaTarget(0);
      d.fx = undefined;
      d.fy = undefined;
    }


    // make edit-menu draggable 
    dragElement(document.getElementById("details-link"))

    function dragElement(elmnt) {
      var pos1 = 0,
        pos2 = 0,
        pos3 = 0,
        pos4 = 0;
      if (document.getElementById(elmnt.id + "-draggable")) {
        // if present, the header is where you move the DIV from:
        document.getElementById(elmnt.id + "-draggable").onmousedown = dragMouseDown;
      } else {
        // otherwise, move the DIV from anywhere inside the DIV:
        elmnt.onmousedown = dragMouseDown;
      }

      function dragMouseDown(e) {
        e = e || window.event;
        e.preventDefault();
        // get the mouse cursor position at startup:
        pos3 = e.clientX;
        pos4 = e.clientY;
        document.onmouseup = closeDragElement;
        // call a function whenever the cursor moves:
        document.onmousemove = elementDrag;
      }

      function elementDrag(e) {
        e = e || window.event;
        e.preventDefault();
        // calculate the new cursor position:
        pos1 = pos3 - e.clientX;
        pos2 = pos4 - e.clientY;
        pos3 = e.clientX;
        pos4 = e.clientY;
        // set the element's new position:
        elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
        elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
      }

      function closeDragElement() {
        // stop moving when mouse button is released:
        document.onmouseup = null;
        document.onmousemove = null;
      }
    }
  </script>

</body>

</html>

【问题讨论】:

    标签: javascript html d3.js


    【解决方案1】:

    对于那些可能会遇到其他问题的人,我发现我的思维错误。我试图获取选择条目的标签而不是应该使用的键。

    在我有之前:

    var linkTypes = {
            "1": "using",
            "2": "need"
        }
    

    我改成了:

    var linkTypes = {
                "using": "using",
                "need": "need"
            }
    

    我还可以使用:

    document.getElementById("details-link-type-selection").value = d.type
    

     d.type = document.getElementById("details-link-type-selection").value
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-07
      相关资源
      最近更新 更多