【发布时间】:2018-01-09 21:35:44
【问题描述】:
我有一个多线图,当按每个水果过滤时会更新。每条线的颜色对应不同的销售年份。在Shashank 的帮助下,每个数据点线上的圆圈已添加到组中,而不是直接附加到 SVG。这是一个显示这个的sn-p:
var dataAsCsv = `Month,Sales,Fruit,Year
Jan,87,strawberry,2016
Feb,3,strawberry,2016
Mar,89,strawberry,2016
Apr,56,strawberry,2016
May,1,strawberry,2016
Jun,17,strawberry,2016
Jul,59,strawberry,2016
Aug,43,strawberry,2016
Sep,16,strawberry,2016
Oct,94,strawberry,2016
Nov,99,strawberry,2016
Dec,53,strawberry,2016
Jan,93,grape,2016
Feb,8,grape,2016
Mar,95,grape,2016
Apr,62,grape,2016
May,5,grape,2016
Jun,24,grape,2016
Jul,62,grape,2016
Aug,49,grape,2016
Sep,18,grape,2016
Oct,101,grape,2016
Nov,103,grape,2016
Dec,53,grape,2016
Jan,94,blueberry,2016
Feb,15,blueberry,2016
Mar,95,blueberry,2016
Apr,64,blueberry,2016
May,11,blueberry,2016
Jun,33,blueberry,2016
Jul,64,blueberry,2016
Aug,53,blueberry,2016
Sep,27,blueberry,2016
Oct,103,blueberry,2016
Nov,108,blueberry,2016
Dec,62,blueberry,2016
Jan,80,strawberry,2015
Feb,0,strawberry,2015
Mar,71,strawberry,2015
Apr,51,strawberry,2015
May,3,strawberry,2015
Jun,11,strawberry,2015
Jul,56,strawberry,2015
Aug,34,strawberry,2015
Sep,12,strawberry,2015
Oct,75,strawberry,2015
Nov,94,strawberry,2015
Dec,46,strawberry,2015
Jan,76,grape,2015
Feb,0,grape,2015
Mar,78,grape,2015
Apr,58,grape,2015
May,10,grape,2015
Jun,22,grape,2015
Jul,47,grape,2015
Aug,36,grape,2015
Sep,18,grape,2015
Oct,86,grape,2015
Nov,98,grape,2015
Dec,40,grape,2015
Jan,79,blueberry,2015
Feb,0,blueberry,2015
Mar,78,blueberry,2015
Apr,49,blueberry,2015
May,5,blueberry,2015
Jun,31,blueberry,2015
Jul,62,blueberry,2015
Aug,49,blueberry,2015
Sep,7,blueberry,2015
Oct,86,blueberry,2015
Nov,100,blueberry,2015
Dec,46,blueberry,2015`;
// Set the margins
var margin = {top: 60, right: 100, bottom: 20, left: 80},
width = 850 - margin.left - margin.right,
height = 370 - margin.top - margin.bottom;
//Legend sizing
var legendRectSize = 18;
var legendSpacing = 4;
// Parse the month variable
var parseMonth = d3.timeParse("%b");
var formatMonth = d3.timeFormat("%b");
var formatYear = d3.timeFormat("%Y");
var parseYear = d3.timeParse("%Y");
// Set the ranges
var x = d3.scaleTime().domain([parseMonth("Jan"), parseMonth("Dec")]).range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
var colors = d3.scaleOrdinal()
.domain(["2016", "2015"])
.range(["#00BFFF", "#87CEFA"]);
// Define the line
var valueLine = d3.line()
.x(function(d) { return x(d.Month); })
.y(function(d) { return y(+d.Sales); })
// Define the div for the tooltip
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
// Create the svg canvas in the "graph" div
var svg = d3.select("#graph")
.append("svg")
.style("width", width + margin.left + margin.right + "px")
.style("height", height + margin.top + margin.bottom + "px")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform","translate(" + margin.left + "," + margin.top + ")")
.attr("class", "svg");
var data = d3.csvParse(dataAsCsv);
// Format the data
data.forEach(function(d) {
d.Month = parseMonth(d.Month);
d.Sales = +d.Sales;
d.Fruit = d.Fruit;
d.Year = formatYear(parseYear(+d.Year));
});
var nest = d3.nest()
.key(function(d){
return d.Fruit;
})
.key(function(d){
return d.Year;
})
.entries(data)
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.Month; }));
y.domain([0, d3.max(data, function(d) { return d.Sales; })]);
// Set up the x axis
var xaxis = svg.append("g")
.attr("transform", "translate(0," + height + ")")
.attr("class", "x axis")
.style("font-family", "Courier New")
.call(d3.axisBottom(x)
.ticks(d3.timeMonth)
.tickSize(0, 0)
.tickFormat(d3.timeFormat("%B"))
.tickSizeInner(0)
.tickPadding(10));
// Add the Y Axis
var yaxis = svg.append("g")
.attr("class", "y axis")
.style("font-family", "Courier New")
.call(d3.axisLeft(y)
.ticks(5)
.tickSizeInner(0)
.tickPadding(6)
.tickSize(0, 0));
// Add a label to the y axis
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - 60)
.attr("x", 0 - (height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Monthly Sales")
.attr("class", "y axis label")
.style("font-family", "Courier New")
.style("font-size", "11px");
//Add Title
svg.append("text")
.attr("y", 0)
.attr("x", width/2)
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Fruit Sales")
.attr("class", "y axis label")
.style("font-family", "Courier New")
.style("font-size", "20px");
svg.append('g').classed('data-points', true);
// Create a dropdown
var fruitMenu = d3.select("#fruitDropdown")
fruitMenu
.append("select")
.selectAll("option")
.data(nest)
.enter()
.append("option")
.attr("value", function(d){
return d.key;
})
.text(function(d){
return d.key;
})
// Function to create the initial graph
var initialGraph = function(fruit){
// Filter the data to include only fruit of interest
var selectFruit = nest.filter(function(d){
return d.key == fruit;
})
var selectFruitGroups = svg.selectAll(".fruitGroups")
.data(selectFruit, function(d){
return d ? d.key : this.key;
})
.enter()
.append("g")
.attr("class", "fruitGroups")
var initialPath = selectFruitGroups.selectAll(".line")
.data(function(d) { return d.values; })
.enter()
.append("path")
.attr("stroke", function(d){ return colors(d.key)});
initialPath
.attr("d", function(d){
return valueLine(d.values)
})
.attr("class", "line")
svg.select('g.data-points').selectAll("dot")
.data(data.filter(function(d) {
return d.Fruit === fruit;
}))
.enter().append("circle").classed('dot', true)
.attr("r", 3)
.attr("fill", function(d){ return colors(d.key)})
.attr("cx", function(d) { return x(d.Month); })
.attr("cy", function(d) { return y(+d.Sales); })
.on("mouseover", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div .html("Sales:" + " " + d.Sales)
.style("font-family", "Courier New")
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
});
}
// Create initial graph
initialGraph("strawberry")
// Update the data
var updateGraph = function(fruit){
// Filter the data to include only fruit of interest
var selectFruit = nest.filter(function(d){
return d.key == fruit;
})
// Select all of the grouped elements and update the data
var selectFruitGroups = svg.selectAll(".fruitGroups")
.data(selectFruit)
// Select all the lines and transition to new positions
selectFruitGroups.selectAll("path.line")
.data(function(d){
return (d.values);
})
.transition()
.duration(1000)
.attr("d", function(d){
return valueLine(d.values)
});
var circles = svg.select('g.data-points').selectAll(".dot")
.data(data.filter(function(d) {
return d.Fruit === fruit;
}));
circles
.enter().append("circle")
.merge(circles).classed('data-point', true)
.attr("r", 3)
.attr("fill", function(d){ return colors(d.key)})
.transition().duration(1000)
.attr("cx", function(d) { return x(d.Month); })
.attr("cy", function(d) { return y(+d.Sales); });
}
var legend = svg.selectAll('.legend')
.data(colors.domain()) // NEW
.enter() // NEW
.append('g') // NEW
.attr('class', 'legend') // NEW
.attr('transform', function(d, i) { // NEW
var height1 = legendRectSize + legendSpacing; // NEW
var offset = height1 * colors.domain().length /2; // NEW
var horz = 37 * legendRectSize; // NEW
var vert = i * height1 - offset; // NEW
return 'translate(' + horz + ',' + vert + ')'; // NEW
}); // NEW
legend.append('rect') // NEW
.attr('width', legendRectSize) // NEW
.attr('height', legendRectSize) // NEW
.style('fill', colors) // NEW
.style('stroke', colors); // NEW
legend.append('text') // NEW
.attr('x', legendRectSize + legendSpacing) // NEW
.attr('y', legendRectSize - legendSpacing)
.style("font-family", "Courier New")
.text(function(d) { return d; });
// Run update function when dropdown selection changes
fruitMenu.on('change', function(){
// Find which fruit was selected from the dropdown
var selectedFruit = d3.select(this)
.select("select")
.property("value")
// Run update function with the selected fruit
updateGraph(selectedFruit)
});
.line {
fill: none;
stroke-width: 2px;
}
div.tooltip {
position: absolute;
text-align: center;
width: 60px;
height: 28px;
padding: 2px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
.dot:hover {
fill: black;
}
.legend { /* NEW */
font-size: 10px; /* NEW */
} /* NEW */
rect { /* NEW */
stroke-width: 2; /* NEW */
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>D3 Page Template</title>
<script src="https://d3js.org/d3.v4.js"></script>
<link rel="stylesheet" href="style.css">
</head>
<body>
<g class="data-points"></g>
<div id = "fruitDropdown"></div>
<div id="graph"></div>
<script src="Example11.js"></script>
</body>
</html>
如何确保圆圈采用与线条相同的颜色,同时确保在选择不同水果时它们会更新?我希望这个解决方案也能为图例中的额外矩形提供修复。
非常感谢, 詹姆斯
【问题讨论】:
标签: javascript d3.js svg