我花了很多时间尝试在SVG / D3.js中复制附图。我最接近的是使用附加的代码。我已经探索过使用树函数,但只能创建一个圆圈。
附加代码的问题是,通过手动输入每个圆圈必须坐的像素坐标,很难让它看起来平滑和智能。
有关信息,数据集只会为这些圆圈着色,因此在形状方面它可以完全是静态的。代码只需要生成形状,然后我可以根据数据集驱动颜色。
我想要创建的图片:
这是我的代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>D3 Test</title>
<style type="text/css">
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
</head>
<body>
<script type="text/javascript">
//Width and height
var w = 1000;
var h = 1000;
var dataset = [6, 2, 5, 4, 5, 5, 5, 5, 3, 4, 5, 6];
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
var circles = svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle");
circles.attr("cx", function(d, i) {
var Xaxis;
if (i === 0) {
Xaxis = "500";
} else if (i === 1) {
Xaxis = "400";
} else if (i === 2) {
Xaxis = "420";
} else if (i === 3) {
Xaxis = "452.5";
} else if (i === 4) {
Xaxis = "485";
} else if (i === 5) {
Xaxis = "515";
} else if (i === 6) {
Xaxis = "547.5";
} else if (i === 7) {
Xaxis = "580";
} else if (i === 8) {
Xaxis = "600";
} else if (i === 9) {
Xaxis = "600";
} else if (i === 10) {
Xaxis = "650";
} else if (i === 11) {
Xaxis = "700";
} else if (i === 12) {
Xaxis = "750";
} else if (i === 13) {
Xaxis = "750";
} else if (i === 14) {
Xaxis = "750";
} else if (i === 15) {
Xaxis = "750";
} else if (i === 16) {
Xaxis = "750";
}
return Xaxis;
})
circles.attr("cy", function(d, i) {
var Yaxis;
if (i === 0) {
Yaxis = "500";
} else if (i === 1) {
Yaxis = "500";
} else if (i === 2) {
Yaxis = "535";
} else if (i === 3) {
Yaxis = "560";
} else if (i === 4) {
Yaxis = "585";
} else if (i === 5) {
Yaxis = "585";
} else if (i === 6) {
Yaxis = "560";
} else if (i === 7) {
Yaxis = "535";
} else if (i === 8) {
Yaxis = "500";
} else if (i === 9) {
Yaxis = "600";
} else if (i === 10) {
Yaxis = "550";
} else if (i === 11) {
Yaxis = "500";
} else if (i === 12) {
Yaxis = "450";
} else if (i === 13) {
Yaxis = "600";
} else if (i === 14) {
Yaxis = "550";
} else if (i === 15) {
Yaxis = "500";
} else if (i === 16) {
Yaxis = "450";
}
return Yaxis;
})
.attr("r", function(d, i) {
var size;
if (i === 0) {
size = "30";
} else if (i > 0) {
size = "20";
}
return size;
})
.attr("fill", function(d, i) {
var returnColor;
if (d === 1) {
returnColor = "green";
} else if (d === 2) {
returnColor = "lightgreen";
} else if (d === 3) {
returnColor = "gold";
} else if (d === 4) {
returnColor = "darkorange";
} else if (d === 5) {
returnColor = "red";
} else if (d === 6) {
returnColor = "lightgrey";
}
return returnColor;
});
</script>
</body>
</html>
&#13;
答案 0 :(得分:7)
您可以使用一些三角法来定位您的圆圈。这就是你需要的:
要将圆圈定位在x轴上:
x-center +(距离* sin(角度))
并将其定位在y轴上:
y-center +(距离* cos(角度))
其中distance
是圆与中心的距离,angle
是以弧度表示的角度。要计算它,请使用:
rad = deg * Math.PI/180;
在下面的代码片段中,我使用组绘制圆圈图层,并使用每个组中圆圈的索引计算角度。我使用d3.range()
设置圆圈数,并设置相同阵列中设置距中心距离的图层数量。检查一下:
var width = height = 500;
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
var color = d3.scaleOrdinal(d3.schemeCategory10)
.domain(d3.range(16));
var data1 = d3.range(16);
var dataRadius = [70, 110, 150, 190, 230];
svg.append("circle").attr("cx", width / 2)
.attr("cy", height / 2)
.attr("r", 20)
.attr("fill", "yellow");
var groups = svg.selectAll(".groups")
.data(dataRadius)
.enter()
.append("g");
var circles = groups.selectAll(".circles")
.data(data1)
.enter()
.append("circle");
circles.attr("cx", function(d, i) {
var radius = this.parentNode.__data__;
return width / 2 + (radius * Math.sin(i * (360 / (data1.length) * Math.PI / 180)))
})
.attr("cy", function(d, i) {
var radius = this.parentNode.__data__;
return height / 2 + (radius * Math.cos(i * (360 / (data1.length) * Math.PI / 180)))
})
.attr("r", function() {
return this.parentNode.__data__ == 230 ? 24 : 14
})
.attr("fill", function(d, i) {
return i == 13 || i == 14 ? color(i - 2) : "#ccc"
});
&#13;
<script src="https://d3js.org/d3.v4.min.js"></script>
&#13;
答案 1 :(得分:2)
虽然这已经有一年了,但我想加上我自己的两分钱,提供一种与Gerardo proposed完全不同的方法。我时不时地提倡使用transform
属性提供的强大的SVG转换。无论如何,这主要是因为没有注意到的原因而被忽视。一个这样的例子是我的answer到"SVG marker - can I set length and angle?"。大多数开发人员似乎更喜欢自己做三角测量,尽管我认为我的解决方案不那么繁琐,并且结果代码更加干净和优雅,而且更直观易用。
为了充分了解正在发生的事情,我鼓励任何不熟悉该主题的人阅读并重新阅读SVG coordinate systems and transformations Sara Soueidan上由组成的优秀三部曲系列。
我将要呈现的方法将所有三角函数卸载到浏览器,从而允许逐字SVG代码。如果你自己计算了圆圈的位置,你将会得到这样的坐标:
<circle cx="314.67156727579004" cy="276.78784026555627"></circle>
可以使用以下行生成相同的圆圈:
<g transform="rotate(30)">
<circle transform="translate(70)"></circle>
</g>
请注意,某些不相关的属性(r
,fill
)已从两个片段中删除,只关注定位。后者更清楚开发人员想要实现的目标:
甚至不需要cx
和cy
属性,因为这些属性默认为0
,允许我们从原点开始,然后通过将其包装在内来偏移整个图形另一组将它翻译成适合的。生成的SVG结构如下:
https://angular.io/api/router/Resolve
请查看以下代码片段以了解正常工作:
const svg = d3.select("svg>g");
const g = svg.selectAll(null)
.data(d3.range(30, 361, 30))
.enter().append("g")
.attr("transform", d => `rotate(${d})`);
g.selectAll(null)
.data(d3.range(40, 171, 30))
.enter().append("circle")
.attr("transform", d => `translate(${d})`)
.attr("r", (d, i) => i === 4 ? 15 : 10)
.attr("fill", "#ccc");
<script src="https://d3js.org/d3.v4.js"></script>
<svg width="600" height="600">
<g transform="translate(200,200)">
</g>
</svg>