好吧,我开始对D3更加熟悉了,但在某些方面我仍然有点朦胧。我现在正在尝试绘制网格线,但我意识到我可能正在进行攻击而不是正确地进行操作。我尝试使用教程添加一些网格线,但最终得到了很多代码,我似乎是为了让它能够正确排列。我想知道是否有人能指出我更好的写作方式......
原始代码是这样的。
<script type="text/javascript">
//Width and height
var w = 800;
var h = 400;
var padding = 20;
var border=1;
var bordercolor='black';
var dataset = [
[5, 20], [480, 90], [250, 50], [100, 33], [330, 95],[-50,-100],[50,-45],
[410, 12], [475, 44], [25, 67], [85, 21], [220, 88],[-480, -467], [3,-90],[468,481]
];
// create scale functions
var xScale = d3.scale.linear()
.domain([d3.min(dataset, function(d) { return d[0]; }), d3.max(dataset, function(d) { return d[0]; })])
.range([padding, w - padding * 2]);
var yScale = d3.scale.linear()
.domain([d3.min(dataset, function(d) { return d[0]; }), d3.max(dataset, function(d) { return d[1]; })])
.range([h - padding, padding]);
var rScale = d3.scale.linear()
.domain( [-100, d3.max(dataset, function(d) { return d[1]; })] )
.range([2,5]);
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h)
.attr("border",border)
;
//define X axis this is rly a function, remember, variables can hold functions in JS
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.ticks(1)
.tickSize(-h, 0, 0)
; //Set rough # of ticks
//Define Y axis
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(1)
.tickSize(-w, 0, 0)
;
//create the circles
svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
.attr("cx", function(d) {
return xScale(d[0]);
})
.attr("cy", function(d) {
return yScale(d[1]);
})
.attr("r", 3);
// draw axes here
svg.append("g")
.attr("class", "axis") //assign "axis" class
.attr("transform", "translate(0," + (h - padding) +")")
.call(xAxis);
svg.append("g")
.attr("class", "axis") //assign "axis" class
.attr("transform", "translate(" + padding + ",0)" )
.call(yAxis);
// end draw axes here
</script>
我在第二个链接中添加的代码在这里
var vis = svg.append("svg:g")
.attr("transform", "translate(20,0)")
var rules = vis.append("svg:g").classed("rules", true)
rules.append("svg:g").classed("grid x_grid", true)
.attr("transform", "translate(-20,"+h+")")
.call(d3.svg.axis()
.scale(xScale)
.orient("bottom")
.ticks(4)
.tickSize(-h,0,0)
.tickFormat("")
)
rules.append("svg:g").classed("grid y_grid", true)
.call(d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(5)
.tickSize(-w,0,0)
.tickFormat("")
)
rules.append("svg:g").classed("labels x_labels", true)
.attr("transform", "translate(-20,"+ h +")")
.call(d3.svg.axis()
.scale(xScale)
.orient("bottom")
.ticks(4)
.tickSize(0)
.tickFormat("")
// .tickFormat(d3.time.format("%Y/%m"))
)
rules.append("svg:g").classed("labels y_labels", true)
.call(d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(5)
.tickSubdivide(1)
.tickSize(0, 0, 0)
.tickFormat("")
)
再次,非常感谢任何帮助
答案 0 :(得分:67)
假设您已定义Mike Bostock's标准margins,并且您已为y轴定义了线性比例,则以下代码将创建水平网格线而不使用tickSize()
。
svg.selectAll("line.horizontalGrid").data(yScale.ticks(4)).enter()
.append("line")
.attr(
{
"class":"horizontalGrid",
"x1" : margin.right,
"x2" : width,
"y1" : function(d){ return yScale(d);},
"y2" : function(d){ return yScale(d);},
"fill" : "none",
"shape-rendering" : "crispEdges",
"stroke" : "black",
"stroke-width" : "1px"
});
答案 1 :(得分:18)
我建议使用d3.svg.axis()。scale()将网格绑定到坐标。我根据您的代码quick example
绘制了http://jsfiddle.net/temirov/Rt65L/1/
要点是使用现有的刻度,x和y,并使用刻度线作为网格。由于yAxis和xAxis已经定义,我们可以重复使用它们。以下是相关代码:
//Draw a grid
var numberOfTicks = 6;
var yAxisGrid = yAxis.ticks(numberOfTicks)
.tickSize(w, 0)
.tickFormat("")
.orient("right");
var xAxisGrid = xAxis.ticks(numberOfTicks)
.tickSize(-h, 0)
.tickFormat("")
.orient("top");
svg.append("g")
.classed('y', true)
.classed('grid', true)
.call(yAxisGrid);
svg.append("g")
.classed('x', true)
.classed('grid', true)
.call(xAxisGrid);
答案 2 :(得分:11)
您可以使用比例尺的ticks()
函数来获取刻度值,然后在数据调用中使用它们来绘制线条。
var ticks = xScale.ticks(4);
rules.selectAll("path.xgrid").data(ticks).enter()
.append("path")
.attr("d", function(d) {
return "M" + xScale(d) + " " + padding + "L" + xScale(d) + " " + (h-padding);
});
您可能更喜欢为网格线使用线生成器,而不是手动创建路径。这对于y网格线的工作方式类似,只是y坐标是常量,范围从0到图的宽度。您可能需要调整开始值和结束值以使其看起来很好&#34;。
答案 3 :(得分:2)
在d3fc项目中,我们创建了一个gridlines component,其渲染方式与D3(v4)轴完全相同。
以下是用法示例:
var width = 500, height = 250;
var container = d3.select("#gridlines")
.append("svg")
.attr("width", width)
.attr("height", height);
var xScale = d3.scaleLinear()
.range([0, 100]);
var yScale = d3.scaleLinear()
.range([0, 100]);
var gridline = fc.annotationSvgGridline()
.xScale(xScale)
.yScale(yScale);
container.append("g")
.call(gridline);
呈现如下:
网格线的间距由相关轴提供的刻度确定。
披露:我是d3fc项目的核心贡献者!
答案 4 :(得分:1)
遵循@ arete的想法,您可以使用以下内容来避免不必要地重新绘制网格线:
function createsGrid(data) {
var grid = gridLine.selectAll("line.horizontalGrid").data(scaleY.ticks());
grid.enter()
.append("line")
.attr("class","horizontalGrid");
grid.exit().remove();
grid.attr({
"x1":0,
"x2": width,
"y1": function (d) { return scaleY(d); },
"y2": function (d) { return scaleY(d); }
});
}
并在CSS文件中定义以下内容
line.horizonalGrid{
fill : none;
shape-rendering : crispEdges;
stroke : black;
stroke-width : 1.5px;
}
答案 5 :(得分:1)
您可以使用innerTickSize而不是tickSize:
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.ticks(1)
.innerTickSize(-h);