我正在使用来自https://gist.github.com/llad/3766585的稍微修改的可重用柱形图脚本
效果很好。但是,我只是想在悬停时添加一些工具提示,这将显示 JSON 文件中每列的附加数据,但附加数据不存在。我查看检查器,只看到用于计算 x 和 y 的两个值。脚本的编写方式是否有明显的东西没有绑定完整的数据集?
剧本:
function columnChart() {
var margin = {top: 30, right: 10, bottom: 50, left: 50},
width = 420,
height = 420,
xRoundBands = 0.2,
xValue = function(d) { return d[0]; },
yValue = function(d) { return d[1]; },
xScale = d3.scale.ordinal(),
yScale = d3.scale.linear(),
xFormat = '',
yFormat = '',
yAxis = d3.svg.axis().scale(yScale).orient("left"),
xAxis = d3.svg.axis().scale(xScale);
function chart(selection) {
selection.each(function(data) {
// Convert data to standard representation greedily;
// this is needed for nondeterministic accessors.
data = data.map(function(d, i) {
return [xValue.call(data, d, i), yValue.call(data, d, i)];
});
// Update the x-scale.
xScale
.domain(data.map(function(d) { return d[0];} ))
.rangeRoundBands([0, width - margin.left - margin.right], xRoundBands);
// Update the y-scale.
yScale
.domain(d3.extent(data.map(function(d) { return d[1];} )))
.range([height - margin.top - margin.bottom, 0])
.nice();
// Select the svg element, if it exists.
var svg = d3.select(this).selectAll("svg").data([data]);
// Otherwise, create the skeletal chart.
var gEnter = svg.enter().append("svg").append("g");
gEnter.append("g").attr("class", "bars");
gEnter.append("g").attr("class", "y axis");
gEnter.append("g").attr("class", "x axis");
gEnter.append("g").attr("class", "x axis zero");
// Update the outer dimensions.
svg .attr("width", width)
.attr("height", height);
// Update the inner dimensions.
var g = svg.select("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// Update the bars.
var bar = svg.select(".bars").selectAll(".bar").data(data);
bar.enter().append("rect");
bar.exit().remove();
bar.attr("class", function(d, i) { return d[1] < 0 ? "bar negative" : "bar positive"; })
.attr("x", function(d) { return X(d); })
.attr("y", function(d, i) { return d[1] < 0 ? Y0() : Y(d); })
.attr("width", xScale.rangeBand())
.attr("height", function(d, i) { return Math.abs( Y(d) - Y0() ); })
.on("click", function(d, i)
{
d3.selectAll('.bar').classed('fade', true);
d3.select(this).classed("sel", true).classed("fade", false);
})
.on("mouseover", function(d, i)
{
d3.select(this).classed("hover", true);
})
.on("mouseout", function(d, i)
{
d3.select(this).classed("hover", false);
});
// x axis at the bottom of the chart
g.select(".x.axis")
.attr("transform", "translate(0," + (height - margin.top - margin.bottom) + ")")
.call(xAxis.orient("bottom").tickFormat(xFormat));
// zero line
g.select(".x.axis.zero")
.attr("transform", "translate(0," + Y0() + ")")
.call(xAxis.tickFormat("").tickSize(0));
// Update the y-axis.
g.select(".y.axis")
.call(yAxis);
// Horizontal grid
g.insert("g", ".bars")
.attr("class", "grid horizontal")
.call(d3.svg.axis().scale(yScale)
.orient("left")
.tickSize(-(width-margin.left-margin.right), 0, 0)
.tickFormat("")
);
});
}
// The x-accessor for the path generator; xScale ∘ xValue.
function X(d) {
return xScale(d[0]);
}
function Y0() {
return yScale(0);
}
// The x-accessor for the path generator; yScale ∘ yValue.
function Y(d) {
return yScale(d[1]);
}
chart.margin = function(_) {
if (!arguments.length) return margin;
margin = _;
return chart;
};
chart.width = function(_) {
if (!arguments.length) return width;
width = _;
return chart;
};
chart.height = function(_) {
if (!arguments.length) return height;
height = _;
return chart;
};
chart.x = function(_) {
if (!arguments.length) return xValue;
xValue = _;
return chart;
};
chart.y = function(_) {
if (!arguments.length) return yValue;
yValue = _;
return chart;
};
chart.yTickFormat = function(_) {
if (!arguments.length) return yFormat;
yFormat = _;
return chart;
};
chart.xTickFormat = function(_) {
if (!arguments.length) return xFormat;
xFormat = _;
return chart;
};
return chart;
}
初始化:
function renderGraph(view){
var chartWidth = mainWidth();
var chartHeight = 400;
var parseDate = d3.time.format("%Y-%m-%d").parse;
var xFormat = d3.time.format("%b %e");
var data = [];
var req = $.ajax({
url: '/data/column-data.json',
type: 'GET',
dataType: 'json',
success: function(response) {
data = response;
}
});
$.when(req).done(function() {
d3.select("#columnChart")
.datum(data.widgets)
.call(columnChart()
.width(chartWidth)
.height(chartHeight)
.x(function(d, i) { return parseDate(d[0]); })
.xTickFormat(xFormat)
.y(function(d, i) {
var yData;
if (view === 'thisView'){
yData = d[1];
}else if (view === 'thatView'){
yData = d[2];
}
return yData;
}));
});
}
数据如下所示:
{ "widgets" : [
["2013-09-15", 1, 66622, 1, 3],
["2013-09-16", 0, 0, 0, 0],
["2013-09-17", 2, 76316, 2, 2],
["2013-09-18", 4, 291244, 8, 12],
["2013-09-19", 1, 74674, 2, 2],
["2013-09-20", 5, 287965, 7, 5],
["2013-09-21", 0, 0, 0, 0],
["2013-09-22", 0, 0, 0, 0],
["2013-09-23", 7, 459249, 15, 22],
["2013-09-24", 2, 317320, 1, 6],
["2013-09-25", 3, 100269, 3, 10],
["2013-09-26", 4, 181080, 8, 4],
["2013-09-27", 1, 38056, 1, 1],
["2013-09-28", 0, 0, 0, 0],
["2013-09-29", 0, 0, 0, 0],
["2013-09-30", 3, 449334, 2, 13],
["2013-10-01", 9, 403929, 5, 15],
["2013-10-02", 4, 222512, 7, 12],
["2013-10-03", 1, 196012, 3, 9],
["2013-10-04", 2, 391716, 2, 8],
["2013-10-05", 0, 0, 0, 0],
["2013-10-06", 0, 0, 0, 0],
["2013-10-07", 4, 260312, 8, 14],
["2013-10-08", 1, 34350, 1, 1],
["2013-10-09", 3, 179067, 9, 18],
["2013-10-10", 2, 124250, 8, 19],
["2013-10-11", 2, 381186, 4, 9],
["2013-10-12", 0, 0, 0, 0],
["2013-10-13", 0, 0, 0, 0],
["2013-10-14", 5, 393400, 11, 17]
]
}
工具提示应显示任何一列的完整数据。网络检查器为每列显示 2 个数组(我期待一个 5 个数组)
如何修改脚本以绑定每列的完整数据?
谢谢!
更新:尽管@adam-pearce 非常接近,但我仍然没有解决这个问题。我已经整理了几个 jsbin 来提供帮助。
原始脚本的 bin 在这里:http: //jsbin.com/EjugosA/2/edit
亚当回答的脚本在这里:http: //jsbin.com/IPoDutA/1/edit
这只是注释掉了以下内容:
//data = data.map(function(d, i) {
// return [xValue.call(data, d, i), yValue.call(data, d, i)];
//});
您可以在第二个中看到 x 和 y 轴都无法渲染,尽管我想要的完整数据集绑定到每个条。Web 检查器显示以下错误:
'undefined' is not a function (evaluating 'd.getMonth()')" which points to line 8410 in d3.v3.js, in d3_time_formats.
如何修改此脚本以获取完整数据而不破坏轴?