javascript - 如何使 svg 交互以收集对描绘元素的评论/注释

标签 javascript svg networkx graph-theory wikidata

我在 networkx 的帮助下从 wikidata 创建了如下有向图和 nxv .结果是一个 svg 文件,它可能嵌入到一些 html 页面中。
wikidata digraph
现在我希望每个节点和每条边都是“可点击的”,这样用户就可以将他们的评论添加到图形的特定元素中。我认为这可以通过弹出一个模态对话框来完成。这个对话框应该知道它是从哪个元素触发的,并且应该通过 post 请求将 textarea 的内容发送到某个 url。
实现这一目标的最佳方法是什么?

最佳答案

包裹在 W3C standard Web Component (在所有现代浏览器中都支持)您可以将其设为通用 src="filename.svg"

  • 简单示例:How to get SVG document data to be inserted into the DOM?
  • 更复杂的例子:
    <graphviz-svg-annotator src="https://graphviz.org/Gallery/directed/fsm.svg">
    </graphviz-svg-annotator>
    
  • SVG 加载了异步获取
  • 节点和边在这个 SO Snippet 中是可点击的
  • 添加您自己的更好的模式、窗口并保存到数据库
  • 尝试以下 SVG:https://graphviz.org/Gallery/directed/Genetic_Programming.html

  • <graphviz-svg-annotator src="fsm.svg"></graphviz-svg-annotator>
    <graphviz-svg-annotator src="Linux_kernel_diagram.svg"></graphviz-svg-annotator>
    <style>
      svg .annotate { cursor:pointer }
    </style>
    <script>
      customElements.define('graphviz-svg-annotator', class extends HTMLElement {
        constructor() {
          let loadSVG = async ( src , container = this.shadowRoot ) => {
            container.innerHTML = `<style>:host { display:inline-block }
                                   ::slotted(svg)  { width:100%;height:200px }
                                   </style>
                                   <slot name="svgonly">Loading ${src}</slot>`;
            this.innerHTML = await(await fetch(src)).text(); // load full XML in lightDOM
            let svg = this.querySelector("svg");
            svg.slot = "svgonly"; // show only SVG part in shadowDOM slot
            svg.querySelectorAll('g[id*="node"],g[id*="edge"]').forEach(g => {
              let label  = g.querySelector("text")?.innerHTML || "No label";
              let shapes = g.querySelectorAll("*:not(title):not(text)");
              let fill   = (color = "none") => shapes.forEach(x => x.style.fill = color);
              let prompt = "Please annotate: ID: " + g.id + " label: " + label; 
              g.classList.add("annotate");
              g.onmouseenter = evt => fill("lightgreen");
              g.onmouseleave = evt => fill();
              g.onclick = evt => g.setAttribute("annotation", window.prompt(prompt));
            })
          }
          super().attachShadow({ mode: 'open' });
          loadSVG("//graphviz.org/Gallery/directed/"+this.getAttribute("src"));
        }});
    </script>

    详细:
  • this.innerHTML = ...在组件中注入(inject)完整的 XML 光域
    (因为元素有shadowDOM,所以lightDOM在浏览器中是不可见的)
  • 但是您只想要 SVG 部分(graphviz XML 有太多数据)……而且您不想要屏幕闪烁;这就是我将 XML .. invisible.. 放在 lightDOM 中的原因
  • 一个 shadowDOM <slot>仅用于 反射(reflect) <svg>
  • 使用这种方法,<svg>仍然可以从 设置样式全局 CSS (见 cursor:pointer)
  • 屏幕上有多个 SVG <g> ID 值可能会发生冲突。
    完整的 SVG 可以是 移动 到 shadowDOM:
     let svg = container.appendChild( this.querySelector("svg") );
    
    但是你不能再用全局 CSS 为 SVG 设置样式,因为全局 CSS 不能为 shadowDOM 设置样式
  • 关于javascript - 如何使 svg 交互以收集对描绘元素的评论/注释,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66263255/

    相关文章:

    xml - 我如何将多路径 svg 转换为一个路径

    python - 从显示中删除 matplotlib 弃用警告

    networkx - 彩色图同构?

    python - 如何在一个文件中存储多个networkx图?

    javascript - Vue 模板不更新

    javascript - 单击按钮时的 LocalStorage

    javascript - 将 ruby​​ 中的哈希数组中的数据传递到 javascript 完整日历中

    html - SVG <使用> 与 xlink :href is not working in Edge

    javascript - 从网页结果中提取 URL 并在 Iframe 中显示该 URL

    javascript - D3 - 附加矩形停止工具提示工作