【问题标题】:Embedding external SVG in HTML for JavaScript manipulation在 HTML 中嵌入外部 SVG 以进行 JavaScript 操作
【发布时间】:2023-04-08 00:40:01
【问题描述】:

我有一个 SVG 图像,显示地理区域。 http://upload.wikimedia.org/wikipedia/commons/7/71/Nederland_gemeenten_2009.svg

我想在网页上显示 SVG 图像,并结合使用 JavaScript 和 CSS 与图像进行交互。 (即检测区域的点击,为区域设置不同的背景颜色)。

我知道这个问题在 StackOverflow 上被问了好几次,但我找不到完整的代码示例来进一步研究。欢迎任何关于 JavaScript 包(如 jQuery)或插件的建议。

【问题讨论】:

    标签: javascript html svg


    【解决方案1】:

    我对这个问题的理解是有不同的方面需要解决:

    1. 如何为交互准备图像
    2. 如何在页面中嵌入图片
    3. 如何在 SVG 中使用 CSS
    4. 如何使用 JavaScript 进行交互

    准备图片

    首先,我建议清理图像。 Inkscape 将所有你不需要的东西留在那里,包括 sodipodi:inkscape: 命名空间中的元素和属性,以及重复和/或冗余的样式属性。您不必删除它,但它可以为您节省一些带宽/加载时间,而且如果您想使用 CSS 样式表,那么样式属性会妨碍您。

    在您的示例文件中,您有 472 次相同的样式属性。将它们全部删除并创建一个等效的 CSS 规则一次。

    您还可以在标记中添加一些有关市政当局的信息。你可以例如根据名称更改代表自治市的每条路径的 ID。为此,您还可以使用data-* 属性。后者的优点是您可以使用空格。请参阅下文,了解这对交互有何用处,尤其是在使用 CSS 时。

    嵌入图片

    我建议使用 SVG 内联,特别是如果您想与 CSS/JavaScript 交互。这意味着,您只需将 SVG 标记添加到 HTML,或者使用 Ajax 加载和插入它。后者的好处是周围页面加载速度更快,响应速度更快。

    内联 SVG 元素的示例:

    <div id="svgContainer">
      <!-- This is an HTML div, and inside goes the SVG -->
      <svg xmlns="http://www.w3.org/2000/svg" width="100px" height="100px">
        <circle r="50" cx="50" cy="50" fill="green"/>
      </svg>
    </div>
    

    如何使用 Ajax 加载 SVG 的简化示例:

    xhr = new XMLHttpRequest();
    xhr.open("GET","my.svg",false);
    // Following line is just to be on the safe side;
    // not needed if your server delivers SVG with correct MIME type
    xhr.overrideMimeType("image/svg+xml");
    xhr.onload = function(e) {
      // You might also want to check for xhr.readyState/xhr.status here
      document.getElementById("svgContainer")
        .appendChild(xhr.responseXML.documentElement);
    };
    xhr.send("");
    

    如何使用 CSS

    SVG 可以像 HTML 一样设置样式。当然,SVG 有自己的一组属性,例如fill-opacitystroke-dasharray,并且不支持很多HTML 的属性,例如marginposition 等。但是选择器机制是 100% 相同的。

    您可以在 &lt;style&gt; 元素或外部 CSS 文件中混合使用内联 SVG 的 CSS 和 HTML 的 CSS。您还可以在 SVG 代码中使用 &lt;style&gt; 元素和 style 属性。

    假设您为 SVG 元素提供了有意义的 ID 或 data-* 属性,使用 CSS 突出显示城市的两种方法是:

    #Bronckhorst, #Laarbeek {fill:red}
    

    *[data-gemeente=Bronckhorst], *[data-gemeente=Laarbeek] {fill:red}
    

    或者,当然,您可以更改各个元素的样式属性。属性也支持作为属性,即style="stroke-width:2" 也可以像stroke-width="2" 一样指定。如果同时使用属性和 CSS(使用样式属性、样式元素或外部样式表)设置相同的属性,则 CSS 会覆盖该属性。

    JavaScript 交互

    HTML 和 SVG 在 JavaScript 交互方面基本上没有区别,至少只要您使用普通的 DOM。这意味着,SVG 不支持像 innerHTML 这样的 HTML 特定功能(即没有 innerSVG)。但 SVG 有自己的图形特定 DOM 方法集 (see the W3C specs)。

    需要注意的一点是名称空间的使用。所有 SVG 元素都应该在 SVG 命名空间中,并且在使用 JavaScript 创建它们时,必须使用 createElementNS() 而不是 createElement()

    var use = document.createElementNS("http://www.w3.org/2000/svg","use")
    

    同样,XLink 命名空间(即xlink:href)中的属性必须使用setAttributeNS() 而不是setAttribute() 进行操作:

    use.setAttributeNS("http://www.w3.org/1999/xlink","href","#foo")
    

    由于像 jQuery 这样的库部分依赖于 HTML 特定功能,因此在操作 SVG 时避免使用它们会更安全。 [编辑:自从我写下这个答案后,情况可能有所改善。不是 jQuery 用户,我不知道它现在的效果如何。] 还有一些 SVG 特定的库,例如 D3.js,它们可用于特定目的,值得一看。 (当我简单地称它为 SVG 特定库时,我在做 D3.js 不公正,因为它更多)。

    您可以使用onclick 和类似属性以及标准DOM addEventListener()。使用 JavaScript 事件的一个非常简单的示例是向 &lt;svg&gt; 元素添加一个事件侦听器,该元素报告用户单击的城市名称:

    document.getElementsByTagName("svg")[0]
      .addEventListener("click",function(evt){
        alert(evt.target.getAttribute("data-gemeente"))
      },
      false)
    

    旁注:工具提示 使用 SVG 中的 &lt;title&gt; 元素可以实现与在 HTML 中使用 title 属性相同的效果。只需将 &lt;title&gt; 元素放在 SVG 元素中,悬停时,您会看到带有 &lt;title&gt; 元素内容的工具提示。

    <svg xmlns="http://www.w3.org/2000/svg" width="100px" height="100px">
      <rect width="100" height="100">
        <title>test</title>
      </rect>
    </svg>
    

    【讨论】:

    • 所有代码未经测试。如果您有更正,请随时编辑或报告。
    • 这是一个非常完整的答案。我只想补充一点,最好避免将 jQuery 与 SVG 结合使用,因为它假定所有内容都是 HTML,这有时会失败。 IE9+ 支持 DOM 3 的addEventListener,它解决了跨浏览器开发的一些主要难题。 Vanilla js 通常可以完成工作,但如果您想抽象一些 DOM 操作,我建议您使用 D3 d3js.org
    • @Duopixel:谢谢,我添加了一些关于库的信息。
    • @Duopixel:赏金是你吗?非常感谢,实在是太慷慨了。
    • 只是对我会经常回来的答案表示感谢:)
    【解决方案2】:

    仅作记录(知道这晚了一年)我发现 SnapSVG 非常适合 SVG 操作。拉斐尔背后的同一个人:

    http://snapsvg.io

    【讨论】:

      猜你喜欢
      • 2010-09-13
      • 1970-01-01
      • 1970-01-01
      • 2018-10-15
      • 2010-11-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多