我正在学习如何用D3绘制图形,我想在图形上绘制一个或类似的区域,以表明周末的日期与其余的不同(我有附件和图像来解释自己更好) )。我现在所拥有的是我后来展示的小提琴。
正如您所看到的,在数据上,有些日子没有值,并且缺少各自的日期。
JSFiddle我现在所接受的:
default_controller
CSS:
var data = [
{"date":"1-May-13","close":58.13},
{"date":"30-Apr-13","close":53.98},
{"date":"27-Apr-13","close":67.00},
{"date":"26-Apr-13","close":89.70},
{"date":"25-Apr-13","close":99.00},
{"date":"24-Apr-13","close":130.28},
{"date":"23-Apr-13","close":166.70},
{"date":"20-Apr-13","close":234.98},
{"date":"19-Apr-13","close":345.44},
{"date":"18-Apr-13","close":443.34},
];
var margin = {top: 20, right: 50, bottom: 30, left: 50},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var parseDate = d3.time.format("%d-%b-%y").parse,
bisectDate = d3.bisector(function(d) { return d.date; }).left,
formatValue = d3.format(",.2f"),
formatCurrency = function(d) { return "$" + formatValue(d); };
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var line = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.close); });
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
data.forEach(function(d) {
d.date = parseDate(d.date);
d.close = +d.close;
data.sort(function(a, b) {
return a.date - b.date;
});
x.domain([data[0].date, data[data.length - 1].date]);
y.domain(d3.extent(data, function(d) { return d.close; }));
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Price ($)");
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
var focus = svg.append("g")
.attr("class", "focus")
.style("display", "none");
focus.append("circle")
.attr("r", 4.5);
focus.append("text")
.attr("x", 9)
.attr("dy", ".35em");
svg.append("rect")
.attr("class", "overlay")
.attr("width", width)
.attr("height", height)
.on("mouseover", function() { focus.style("display", null); })
.on("mouseout", function() { focus.style("display", "none"); })
.on("mousemove", mousemove);
function mousemove() {
var x0 = x.invert(d3.mouse(this)[0]),
i = bisectDate(data, x0, 1),
d0 = data[i - 1],
d1 = data[i],
d = x0 - d0.date > d1.date - x0 ? d1 : d0;
focus.attr("transform", "translate(" + x(d.date) + "," + y(d.close) + ")");
focus.select("text").text(formatCurrency(d.close));
}
});
我想要完成的图像:
答案 0 :(得分:1)
给出你的x比例域,可以用:
更好地定义x.domain(d3.extent(data, function(d) {
return d.date;
}))
我们可以在第一个日期(x.domain()[0]
)和最后一个日期(x.domain()[1]
)之间的所有星期六填充数组。我们只需要找到星期六:酒吧的宽度将是星期六+ 2天(这将涵盖整个星期六和整个星期天)。
有几个功能可以做到这一点,这里有一个:
function findSat(date1, date2) {
if (date1 > date2) return false;
var saturdays = [];
while (date1 < date2) {
if (date1.getDay() === 6) saturdays.push(new Date(date1));
date1.setDate(date1.getDate() + 1);
}
return saturdays;
}
使用该功能,我们可以在第一个和最后一个日期之间的所有星期六填充一个数组:
var rectDate = findSat(x.domain()[0], x.domain()[1]);
现在,我们使用rectDate
数组来创建矩形:
var rects = svg.selectAll(".rects")
.data(rectDate)
.enter()
.append("rect")
.attr("y", margin.top)
.attr("height", height - margin.bottom)
.attr("x", d => x(d))
.attr("width", d => x(d3.time.day.offset(d, +2)) - x(d))
.attr("fill", "yellow");
请注意,对于宽度,我们从星期六减去“星期六+ 2天”:
.attr("width", d => x(d3.time.day.offset(d, +2)) - x(d))
这是您更新的小提琴:http://jsfiddle.net/36yaot6t/
这里是相同的代码,在Stack片段中:
var data = [{
"date": "1-May-13",
"close": 58.13
}, {
"date": "30-Apr-13",
"close": 53.98
}, {
"date": "27-Apr-13",
"close": 67.00
}, {
"date": "26-Apr-13",
"close": 89.70
}, {
"date": "25-Apr-13",
"close": 99.00
}, {
"date": "24-Apr-13",
"close": 130.28
}, {
"date": "23-Apr-13",
"close": 166.70
}, {
"date": "20-Apr-13",
"close": 234.98
}, {
"date": "19-Apr-13",
"close": 345.44
}, {
"date": "18-Apr-13",
"close": 443.34
}, ];
var margin = {
top: 20,
right: 50,
bottom: 30,
left: 50
},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var parseDate = d3.time.format("%d-%b-%y").parse,
bisectDate = d3.bisector(function(d) {
return d.date;
}).left,
formatValue = d3.format(",.2f"),
formatCurrency = function(d) {
return "$" + formatValue(d);
};
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var line = d3.svg.line()
.x(function(d) {
return x(d.date);
})
.y(function(d) {
return y(d.close);
});
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
data.forEach(function(d) {
d.date = parseDate(d.date);
d.close = +d.close;
});
data.sort(function(a, b) {
return a.date - b.date;
});
x.domain(d3.extent(data, function(d) {
return d.date;
}))
y.domain(d3.extent(data, function(d) {
return d.close;
}));
function findSat(date1, date2) {
if (date1 > date2) return false;
var saturdays = [];
while (date1 < date2) {
if (date1.getDay() === 6) saturdays.push(new Date(date1));
date1.setDate(date1.getDate() + 1);
}
return saturdays;
}
var rectDate = findSat(x.domain()[0], x.domain()[1]);
var rects = svg.selectAll(".rects")
.data(rectDate)
.enter()
.append("rect")
.attr("y", margin.top)
.attr("height", height - margin.bottom)
.attr("x", d => x(d))
.attr("width", d => x(d3.time.day.offset(d, +2)) - x(d))
.attr("fill", "yellow");
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Price ($)");
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
var focus = svg.append("g")
.attr("class", "focus")
.style("display", "none");
focus.append("circle")
.attr("r", 4.5);
focus.append("text")
.attr("x", 9)
.attr("dy", ".35em");
svg.append("rect")
.attr("class", "overlay")
.attr("width", width)
.attr("height", height)
.on("mouseover", function() {
focus.style("display", null);
})
.on("mouseout", function() {
focus.style("display", "none");
})
.on("mousemove", mousemove);
function mousemove() {
var x0 = x.invert(d3.mouse(this)[0]),
i = bisectDate(data, x0, 1),
d0 = data[i - 1],
d1 = data[i],
d = x0 - d0.date > d1.date - x0 ? d1 : d0;
focus.attr("transform", "translate(" + x(d.date) + "," + y(d.close) + ")");
focus.select("text").text(formatCurrency(d.close));
}
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
display: none;
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}
.overlay {
fill: none;
pointer-events: all;
}
.focus circle {
fill: none;
stroke: steelblue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>