48

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

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

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

4

2 回答 2

107

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

  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-opacityorstroke-dasharray并且不支持很多 HTML 的属性,比如margin等等position。但是选择器机制是 100% 相同的。

<style>您可以在元素内部或外部 CSS 文件中混合用于内联 SVG 的 CSS 和用于 HTML的 CSS。您还可以在 SVG 代码和属性中使用该<style>元素。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 不支持 HTML 特定功能innerHTML(即没有innerSVG)。但是 SVG 有自己的图形特定的 DOM 方法集(参见 W3C 规范)。

要注意的一件事是使用名称空间。所有 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 事件的一个非常简单的示例是将事件侦听器添加到<svg>报告用户单击的城市名称的元素中:

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

旁注:Toopltips使用SVG 中的元素title可以实现与使用 HTML 中 的属性相同的效果。<title>只需将一个<title>元素放在 SVG 元素中,悬停时,您就会看到一个包含<title>元素内容的工具提示。

<svg xmlns="http://www.w3.org/2000/svg" width="100px" height="100px">
  <rect width="100" height="100">
    <title>test</title>
  </rect>
</svg>
于 2012-12-28T14:23:32.707 回答
8

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

http://snapsvg.io

于 2013-11-30T09:19:48.350 回答