在 HTML 中嵌入外部 SVG 以进行 JavaScript 操作 [英] Embedding external SVG in HTML for JavaScript manipulation
问题描述
我有一个 SVG 图像,显示了地理区域.http://upload.wikimedia.org/wikipedia/commons/7/71/Nederland_gemeenten_2009.svg
我想在网页上显示 SVG 图像,并使用 JavaScript 和 CSS 的组合与图像进行交互.(即,检测区域上的点击,为区域设置不同的背景颜色).
我知道在 StackOverflow 上多次问过这个问题,但我找不到完整的代码示例来进一步研究.欢迎任何关于 JavaScript 包(如 jQuery)或插件的建议.
我对问题的理解是有不同的方面需要解决:
- 如何准备用于交互的图像
- 如何在页面中嵌入图片
- 如何在 SVG 中使用 CSS
- 如何使用 JavaScript 进行交互
准备图像
首先,我建议清理图像.Inkscape 会留下您不需要的所有类型的东西,其中包括 sodipodi:
和 inkscape:
命名空间中的元素和属性以及重复和/或冗余样式属性.您不必删除它,但它可以为您节省一些带宽/加载时间,而且如果您想使用 CSS 样式表,那么样式属性会阻碍您的工作.
在您的示例文件中,您有 472 次相同的样式属性.删除所有这些并创建一个等效的 CSS 规则.
您还可以在标记中添加一些有关市政当局的信息.你可以例如根据名称更改代表自治市的每条路径的 ID.为此,您还可以使用 data-*
属性.后者的优点是可以使用空格.请参阅下文,了解这对交互有何用处,尤其是与 CSS 交互时.
嵌入图片
我建议使用内联 SVG,尤其是当您想与 CSS/JavaScript 交互时.这意味着,您只需将 SVG 标记添加到您的 HTML,或者您使用 Ajax 加载和插入它.后者的好处是周围页面加载速度更快,响应速度更快.
内联 SVG 元素的示例:
<!-- 这是一个 HTML div,里面是 SVG --><svg xmlns="http://www.w3.org/2000/svg";宽度=100像素"高度=100像素"><圆r=50"cx=50"cy=50"填充=绿色"/></svg>
如何使用 Ajax 加载 SVG 的简化示例:
xhr = new XMLHttpRequest();xhr.open(GET",my.svg",false);//以下行只是为了安全起见;//如果您的服务器提供具有正确 MIME 类型的 SVG,则不需要xhr.overrideMimeType("image/svg+xml");xhr.onload = 函数(e){//您可能还想在此处检查 xhr.readyState/xhr.statusdocument.getElementById(svgContainer").appendChild(xhr.responseXML.documentElement);};xhr.send("");
如何使用 CSS
SVG 可以像 HTML 一样设置样式.当然,SVG 有它自己的一组属性,比如 fill-opacity
或 stroke-dasharray
并且不支持很多 HTML 的属性,比如 margin
、position
等.但是选择器机制是 100% 相同的.
您可以在 <style>
元素或外部 CSS 文件中混合使用内联 SVG 的 CSS 和 HTML 的 CSS.您还可以在 SVG 代码和 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 交互方面基本上没有区别,至少只要您使用普通的 vanilla DOM.这意味着,SVG 不支持像 innerHTML
这样的 HTML 特定功能(即没有 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(点击",function(evt){警报(evt.target.getAttribute(数据-gemeente"))},错误的)
旁注:工具提示使用 SVG 中的 <title>
元素可以实现在 HTML 中使用 title
属性获得的相同效果.只需将
元素放在 SVG 元素中,悬停时,您会看到带有
元素内容的工具提示.
I have a SVG image, showing geographical regions. http://upload.wikimedia.org/wikipedia/commons/7/71/Nederland_gemeenten_2009.svg
I want to display the SVG image on a webpage, and using a combination of JavaScript and CSS to interact with the image. (ie, detect clicks on a region, setting a different background color for a region).
I know this question is asked several times on StackOverflow, but I cannot find a complete code sample to work on further. Any recommendations on JavaScript packages, like jQuery, or plug-ins are welcome.
My understanding of the question is that there are different aspects to be solved:
- How to prepare the image for interaction
- How to embed the image in the page
- How to use CSS with SVG
- How to use JavaScript for interaction
Preparing the image
First of all, I'd recommend to clean up the image. Inkscape leaves all kind of stuff there that you don't need, which includes elements and attributes in the sodipodi:
and inkscape:
namespaces as well as repetitive and/or redundant style attributes. You don't have to remove that, but it saves you some bandwidth/loading time, and if you want to work with CSS stylesheets, than the style attributes are in your way.
In your example file, you have 472 times the same style attribute. Remove all of them and create an equivalent CSS rule once.
You might also add some info about the municipalities to the markup. You could e.g. change the IDs of each path representing a municipality according to its name. You could also use a data-*
attribute for this purpose. The latter has the advantage that you can use spaces. See below for how this is useful for interaction, especially with CSS.
Embedding the image
I'd recommend using the SVG inline, especially if you want to interact with CSS/JavaScript. This means, you just add the SVG markup to your HTML, or you load and insert it using Ajax. The latter has the benefit that the surrounding page loads faster and feels more responsive.
An example of an inline SVG element:
<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>
A simplified example of how to load SVG using Ajax:
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("");
How to use CSS
SVG can be styled just like HTML. Of course, SVG has it's own set of properties, like fill-opacity
or stroke-dasharray
and does not support a lot of HTML's properties, like margin
, position
or the like. But the selector mechanisms are 100% the same.
You can mix the CSS for your inline SVG with the CSS for your HTML, either inside a <style>
element or an external CSS file. You can also use the <style>
element inside the SVG code and style
attributes.
Assuming you gave your SVG elements meaningful IDs or data-*
attributes, two ways of highlighting municipalities using CSS would be:
#Bronckhorst, #Laarbeek {fill:red}
or
*[data-gemeente=Bronckhorst], *[data-gemeente=Laarbeek] {fill:red}
Or, of course, you can change the style attributes of the respective elements. Properties are also supported as attribute, i.e. style="stroke-width:2"
can also be specified like stroke-width="2"
. If the same property is set using both an attribute and CSS (either using the style attribute, a style element or an external stylesheet), the CSS overrides the attribute.
JavaScript interaction
There is basically no difference between HTML and SVG regarding JavaScript interaction, at least as long as you use plain vanilla DOM. This means, HTML specific features like innerHTML
are not supported in SVG (i.e. there is no innerSVG
). But SVG has its own graphics specific set of DOM methods (see the W3C specs).
One thing to be aware of is the work with namespaces. All SVG elements should be in the SVG namespace, and when creating them using JavaScript, createElementNS()
has to be used instead of createElement()
:
var use = document.createElementNS("http://www.w3.org/2000/svg","use")
Likewise, attributes in the XLink namespace (namely xlink:href
) have to be manipulated using setAttributeNS()
instead of setAttribute()
:
use.setAttributeNS("http://www.w3.org/1999/xlink","href","#foo")
As libraries like jQuery partly rely on HTML specific features, it's safer to avoid them when manipulating SVG. [EDIT: The situation might have improved since I wrote this answer. Not being a jQuery user, I don't know how well it works nowadays.] There are also SVG specific libraries like D3.js which can be useful for specific purposes and are worth a look. (I'm doing D3.js injustice when simply calling it an SVG specific library, because it's more).
You can use onclick
and similar attributes and standard DOM addEventListener()
. A very simple example of using JavaScript events would be to add an event listener to the <svg>
element that reports the name of a municipality that a user clicked on:
document.getElementsByTagName("svg")[0]
.addEventListener("click",function(evt){
alert(evt.target.getAttribute("data-gemeente"))
},
false)
Side note: Toopltips
The same effect that you get using the title
attribute in HTML can be achieved using the <title>
element in SVG. Just put a <title>
element inside an SVG element and on hover, you see a tooltip with the content of the <title>
element.
<svg xmlns="http://www.w3.org/2000/svg" width="100px" height="100px">
<rect width="100" height="100">
<title>test</title>
</rect>
</svg>
这篇关于在 HTML 中嵌入外部 SVG 以进行 JavaScript 操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!