我有一个可缩放的旭日形图表,其中包含以下问题:
图例垂直显示而不是水平显示。我认为浮动:留在类传奇上就可以了,但标签显示在新行上。
允许用户在图例中禁用类别以重新计算旭日形图。
工具提示未显示。我错过了什么?
我想在圆环中间追加总计,在变焦过渡时动态变化。怎么去那个?
我为凌乱的代码道歉。我在两周前开始学习D3,下面的代码是一堆不同的教程和堆栈溢出论坛。
提前谢谢!
// define json object
var root = {
"name": "TOTAL",
"children": [
{
"name": "UNASSIGNED",
"children": [
{"name": "high", "size": 170},
{"name": "med", "size": 701},
{"name": "low", "size": 410}
]
},
{
"name": "CLOSED",
"children": [
{"name": "high", "size": 1701},
{"name": "med", "size": 584},
{"name": "low", "size": 606}
]
},
{
"name": "ATTACHED",
"children": [
{"name": "high", "size": 220},
{"name": "med", "size": 179},
{"name": "low", "size": 322}
]
},
{
"name": "NOTIFIED",
"children": [
{"name": "high", "size": 883},
{"name": "med", "size": 132},
{"name": "low", "size": 1066}
]
},
{
"name": "INTEGRATED",
"children": [
{"name": "high", "size": 883},
{"name": "med", "size": 132},
{"name": "low", "size": 416}
]
},
{
"name": "DELIVERED",
"children": [
{"name": "high", "size": 170},
{"name": "med", "size": 701},
{"name": "low", "size": 410}
]
},
{
"name": "ESCALATED",
"children": [
{"name": "high", "size": 170},
{"name": "med", "size": 701},
{"name": "low", "size": 410}
]
},
{
"name": "COMMITTED",
"children": [
{"name": "high", "size": 170},
{"name": "med", "size": 701},
{"name": "low", "size": 410}
]
},
{
"name": "VERIFIED",
"children": [
{"name": "high", "size": 170},
{"name": "med", "size": 701},
{"name": "low", "size": 410}
]
},
{
"name": "SUBMITTED",
"children": [
{"name": "high", "size": 170},
{"name": "med", "size": 701},
{"name": "low", "size": 410}
]
}
]
}
// set width, height, and radius
var width = 650,
height = 475,
radius = (Math.min(width, height) / 2) - 10; // lowest number divided by 2. Then subtract 10
// legend dimensions
var legendRectSize = 15; // defines the size of the colored squares in legend
var legendSpacing = 6; // defines spacing between squares
var formatNumber = d3.format(",d"); // formats floats
var x = d3.scaleLinear() // continuous scale. preserves proportional differences
.range([0, 2 * Math.PI]); // setting range from 0 to 2 * circumference of a circle
var y = d3.scaleSqrt() // continuous power scale
.range([0, radius]); // setting range from 0 to radius
// setting color scheme
var color = {
'TOTAL': '#FFF',
'UNASSIGNED': '#DADFE1',
'ASSIGNED_TO_EDITOR': '#5BCAFF',
'ATTACHED': '#87D37C',
'ASSIGNED_TO_MENTOR': '#F64747',
'ASSIGNED_TO_REVIEWER': '#7BDDDD',
'ASSIGNED_TO_APPROVER': '#1e90ff',
'INTEGRATION_FAILED': '#F1A9A0',
'DELIVERED': '#4183D7',
'INTEGRATED': '#90C695',
'PUBLISHED': '#E4F1FE',
'COMMIT_FAILED': '#F62459',
'NOTIFIED': '#4ECDC4',
'BLOCKED': '#D24D57',
'ESCALATED': '#DB0A5B',
'SUBMITTED': '#86a531',
'REVIEWED': '#bfba00',
'APPROVED': '#C86DEF',
'ASSIGNED_TO_VERIFIER': '#D2527F',
'COMMITTED': '#5AD427',
'VERIFIED': '#81CFE0',
'CLOSED': '#CF000F'
};
var partition = d3.partition(); // subdivides layers
// define arcs
var arc = d3.arc()
.startAngle(function(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x0))); })
.endAngle(function(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x1))); })
.innerRadius(function(d) { return Math.max(0, y(d.y0)); })
.outerRadius(function(d) { return Math.max(0, y(d.y1)); });
// define tooltip
var tooltip = d3.select('body') // select element in the DOM with id 'chart'
.append('div') // append a div element to the element we've selected
.style("opacity","0")
.style("position","absolute");
tooltip.append('div') // add divs to the tooltip defined above
.attr('class', 'label'); // add class 'label' on the selection
tooltip.append('div') // add divs to the tooltip defined above
.attr('class', 'count'); // add class 'count' on the selection
tooltip.append('div') // add divs to the tooltip defined above
.attr('class', 'percent'); // add class 'percent' on the selection
// define SVG element
var svg = d3.select("#chart").append("svg")
.attr("width", width) // set width
.attr("height", height) // set height
.append("g") // append g element
.attr("transform", "translate(" + width / 2 + "," + (height / 2) + ")");
root = d3.hierarchy(root);
root.sum(function(d) { return d.size; });// must call sum on the hierarchy first
var path = svg.selectAll("path")
.data(partition(root).descendants()) // path for each descendant
.enter().append("path")
.attr("d", arc) // draw arcs
.style("fill", function (d) { return color[(d.children ? d : d.parent).data.name]; })
.on("click", click)
.append("title")
.text(function(d) { return d.data.name + "\n" + formatNumber(d.value);
});
// mouse event handlers are attached to path so they need to come after its definition
path.on('mouseover', function(d) { // when mouse enters div
var total = d.data.size
var percent = Math.round(1000 * d.value / total) / 10; // calculate percent
tooltip.select('.label').html(d.data.name); // set current label
tooltip.select('.count').html(total); // set current count
tooltip.select('.percent').html(percent + '%'); // set percent calculated above
tooltip.style('display', 'block'); // set display
});
path.on('mouseout', function() { // when mouse leaves div
tooltip.style('display', 'none'); // hide tooltip for that element
});
path.on('mousemove', function(d) { // when mouse moves
tooltip.style('top', (d3.event.layerY + 10) + 'px') // always 10px below the cursor
.style('left', (d3.event.layerX + 10) + 'px'); // always 10px to the right of the mouse
});
function click(d) {
svg.transition()
.duration(750)
.tween("scale", function() {
var xd = d3.interpolate(x.domain(), [d.x0, d.x1]),
yd = d3.interpolate(y.domain(), [d.y0, 1]),
yr = d3.interpolate(y.range(), [d.y0 ? 20 : 0, radius]);
return function(t) { x.domain(xd(t)); y.domain(yd(t)).range(yr(t)); };
})
.selectAll("path")
.attrTween("d", function(d) { return function() { return arc(d); }; });
}
d3.select(self.frameElement).style("height", height + "px");
// define legend element
var legendWidth = legendRectSize + legendSpacing; // height of element is the height of the colored square plus the spacing
var width= 500;
var height = 75; // height of element is the height of the colored square plus the spacing
var offset = 80; // vertical offset of the entire legend = height of a single element &
var svgw = 20;
var svgh = 20;
var legendContainer = d3.select("#legend").append("svg")
.attr("width", width) // set width
.attr("height", height) // set height
.append("g") // append g element
.attr("transform", function(d, i) {
return "translate(" + i * 20 + ",0)";
});
var legend = legendContainer.selectAll('.legend') // selecting elements with class 'legend'
.data(d3.entries(color)) // refers to an array of labels from our dataset
.enter() // creates placeholder
.append('g') // replace placeholders with g elements
.attr('class', 'legend') // each g is given a legend class
.style('background-color', 'orange')
.attr('transform', function(d, i) {
return "translate(0," + i * 20 + ")" //return translation
});
// adding colored squares to legend
legend.append('rect') // append rectangle squares to legend
.attr('x', 0)
.attr('y', 0)
.attr('width', 10) // width of rect size is defined above
.attr('height', 10) // height of rect size is defined above
.style('fill', function (d) { return color[d.key]; }) // each fill is passed a color
// adding text to legend
legend.append('text')
.attr('x', 20)
.attr('y', 10)
.attr("text-anchor", "start")
.text(function(d) { return d.key; }); // return label
function getRootmostAncestorByWhileLoop(node) {
while (node.depth > 1) node = node.parent;
return node;
}
html, body {
height: 100%;
}
path {
stroke: #fff;
}
/* legend */
#legend {
background-color:yellow;
}
.legend {
font-size: 14px;
float: left;
margin-right:1em;
}
rect {
stroke-width: 2;
}
/* #tooltip {
position: absolute;
width: 200px;
height: auto;
padding: 10px;
background-color: white;
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
-webkit-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4);
-moz-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4);
box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4);
pointer-events: none;
}
#tooltip.hidden {
display: none;
}
#tooltip p {
margin: 0;
font-family: sans-serif;
font-size: 16px;
line-height: 20px;
} */
.tooltip {
opactiy: 0;
positon: absolute;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>D3.js Donut Chart</title>
<link href="https://fonts.googleapis.com/css?family=Open+Sans+Condensed:300|Pacifico" rel="stylesheet">
<link href="styles.css" rel="stylesheet">
</head>
<body>
<div id="chart"></div>
<div id="tooltip" class="hidden">
<p><span id="category"><strong>Important Label Heading</strong></span></p>
<p><span id="value">100</span></p>
</div>
<div id="legend"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.11.0/d3.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.11.0/d3.min.js"></script>
<script src="script.js"></script> <!-- remove if no javascript -->
</body>
</html>
答案 0 :(得分:0)
这是一个有效的演示:
SUNBURST CHART WITH HTML LEGENDS AND TOOLTIP
float
,background-color
等CSS属性不适用于SVG元素。要使用SVG实现这一点,您必须使用将从左侧转换的'transform('+(i*100)+',0)'
。看看docs for the transform attribute.
但是会有两个主要问题:
a)值100
,它不会根据各自的宽度正确对齐文本(即它们会重叠,看起来很糟糕)。
一个解决方案就是根据每个键的宽度计算来定位图例。
b)您必须根据页面宽度计算位置,即图例包装必须手动完成。 SVG 元素不要介意离开页面:P
要克服上述问题,转换为 HTML 在这里是有道理的。它现在只有<div>
和<span>
。
因此,CSS将在下面的行中(检查代码的详细信息):
div#legend .rect {
width: 10px;
height: 10px;
margin-right: 4px;
display: inline-block;
}
对于基于图例的数据过滤点击,这就是要编写的一些代码。我建议你先试试,如果你遇到任何问题,请回来。对不起,写一个问题的整个代码是不可取的。但是我已经给你了起点:
legend.on('click', function(d) {
if(d3.select(this).classed('clicked')) {
d3.select(this).classed('clicked', false)
.style('background-color', function(d) { return color[d.key]; });
// filter data and rerender
} else {
d3.select(this).classed('clicked', true)
.style('background-color', 'transparent');
// filter data and rerender
}
通过点击图例,您会注意到这一点。看看它并尝试根据此key
和重新呈现图表来过滤数据。这也应该相当简单。如果没有,请回复一个新问题。
您的网页上有多个工具提示。我修复了这个bug并添加了一些类和CSS。
var tooltip = d3.select('body') // select element in the DOM with id 'chart'
.append('div').classed('tooltip', true);
我从HTML代码中删除了<div class="tooltip"></div>
。
你能详细说明这一点吗?我不确定这里的要求究竟是什么。也许你可以尝试我创造的小提琴,让我知道如果你在中心贴上那个标签。
希望这有帮助(是的,请修复小错误,如果有的话)。 :)