SVG 的全称是 Scalable Vector Graphics,可缩放矢量图,它是浏览器支持的一种基于 XML 语法的图像格式,SVG 属于声明式绘图系统。
有效的命名空间URI(此命名空间用于标识该节点属于哪种XML类型)
HTML: www.w3.org/1999/xhtml SVG:www.w3.org/2000/svg XBL:www.mozilla.org/xbl XUL:www.mozilla.org/keymaster/g… 一个xml文档可能包含多个软件模块的元素和属性,在不同软件模块中使用相同名称的元素或属性,可能会导致识别和冲突问题,而xml命名空间可以解决该问题。
注意:svg标签的viewBox属性在未设置的时候默认和画布大小(由svg的宽高属性值决定)等同,如果设置了,那么在展示的时候,就会等比缩放,eg:svg的画布大小为200*200,而viewBox的值为“0 0 100 100”则表示在展示的时候会是正常像素的两倍
1、SVG 绘制可视化图表
html部分
<h1 id="title"></h1>
<svg xmlns="http://www.w3.org/2000/svg" class="svg" version="1.1"></svg>
js部分
//初始化数据
initRelation () {
const baseData = await (await fetch('https://s5.ssl.qhres2.com/static/b0695e2dd30daa64.json')).json()
// 将数组内的一级叶子节点全部提取出来作为一个数组
const regions = d3.hierarchy(baseData).sum(d => 1).sort((a, b) => { return b.value - a.value })
const pack = d3.pack().size([400, 300]).padding(1)
const root = pack(regions)
const svg = document.querySelector('.svg')
createSvg(svg, root)
}
//创建xml基本结构
createSvg (dom, node, fillStyle = 'rgba(0, 0, 0, 0.2)', textColor = 'white') {
const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle')
const { x, y, r } = node
circle.setAttribute('cx', x)
circle.setAttribute('cy', y)
circle.setAttribute('r', r)
circle.setAttribute('data-name', node.data.name)
circle.setAttribute('fill', fillStyle)
dom.appendChild(circle)
if (node.children) {
const g = document.createElementNS('http://www.w3.org/2000/svg', 'g')
node.children.forEach((item, index) => {
this.createSvg(g, item)
})
dom.appendChild(g)
} else {
const text = document.createElementNS('http://www.w3.org/2000/svg', 'text')
text.setAttribute('fill', textColor)
text.setAttribute('font-family', 'Arial')
text.setAttribute('font-size', '0.05rem')
text.setAttribute('text-anchor', 'middle')
text.setAttribute('x', x)
text.setAttribute('y', y)
text.textContent = node.data.name
dom.appendChild(text)
}
}
// 使用svg绘制结构层次关系图
drawOfSvg () {
const svg = document.querySelector('.svg')
const title = document.getElementById('title')
let preDom = null
svg.addEventListener('mousemove', (e) => {
let target = e.target
if (target.nodeName === 'text') {
target = target.previousElementSibling
}
const childName = target.getAttribute('data-name')
let parentName = null
if (target.parentNode) {
parentName = target.parentNode.previousElementSibling.getAttribute('data-name')
}
title.textContent = parentName ? parentName + '-' + childName : childName
if (preDom !== target) {
if (preDom) {
preDom.setAttribute('fill', 'rgba(134, 187, 255, .4)')
}
}
target.setAttribute('fill', 'rgba(0, 0, 0, 0.2)')
preDom = target
})
createSvg(svg, this.root)
},
处理后的数据结构
{
"name":"中国",
"children":
[
{
"name":"浙江" ,
"children":
[
{"name":"杭州" },
{"name":"宁波" },
{"name":"温州" },
{"name":"绍兴" }
]
},
{
"name":"广西" ,
"children":
[
{"name":"桂林"},
{"name":"南宁"},
...
}
]
}
实现效果图
注意:
xml语法的结构和html并不相同,并非是html那种层次结构清晰的节点关系,xml语法越是内部的元素越是在结构的后面展示,而非里面