如何在 d3.js 条形图的每个条形图的左上角设置模式原点?
How to set pattern origin at the top left point of each bar of a barchart in d3.js?
我创建了一个条形图并使用模式来填充它。对于每个图案,我设置 x=0 和 y=0,但我不知道这个 (0,0) 点在哪里,所以我不知道我的图案从哪里开始平铺。
我想将条形的左上角设置为每个条形图案的原点。我怎样才能做到这一点?
Diagram of the result I want
我的代码:
<!doctype html>
<html>
<head>
<style>
</style>
<script src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<svg width="600" height="500"></svg>
<svg>
<defs>
<pattern id="pattern1"
x="0" y="0" width="20" height="20"
patternUnits="userSpaceOnUse" >
<circle cx="10" cy="10" r="10" style="stroke: none; fill: #0000ff" />
</pattern>
</defs>
<defs>
<pattern id="pattern2"
x="0" y="0" width="20" height="20"
patternUnits="userSpaceOnUse" >
<circle cx="10" cy="10" r="5" style="stroke: none; fill: #0000ff" />
</pattern>
</defs>
<defs>
<pattern id="pattern3"
x="0" y="0" width="20" height="20"
patternUnits="userSpaceOnUse" >
<circle cx="10" cy="10" r="3" style="stroke: none; fill: #0000ff" />
</pattern>
</defs>
<rect x="0" y="0" width="100" height="100"
style="stroke: #000000; fill: url(#pattern1);" />
<rect x="100" y="0" width="100" height="100"
style="stroke: #000000; fill: url(#pattern2);" />
<rect x="200" y="0" width="100" height="100"
style="stroke: #000000; fill: url(#pattern3);" />
</svg>
</body>
<script>
var data = [{ year: '2001', value:10 },
{ year: '2002', value:30 },
{ year: '2003', value:20 },
]
var svg = d3.select("svg"),
margin = 200,
width = svg.attr("width") - margin,
height = svg.attr("height") - margin
var xScale = d3.scaleBand().range([0, width]).padding(0.4),
yScale = d3.scaleLinear().range([height, 0]);
var g = svg.append("g")
.attr("transform", "translate(" + 100 + "," + 100 + ")");
xScale.domain(data.map(function(d) { return d.year; }));
yScale.domain([0, d3.max(data, function(d) { return d.value; })]);
g.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(xScale));
g.append("g")
.call(d3.axisLeft(yScale).tickFormat(function(d){
return d;
}).ticks(10));
g.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return xScale(d.year); })
.attr("y", function(d) { return yScale(d.value); })
.attr("width", xScale.bandwidth())
.attr("height", function(d) { return height - yScale(d.value); })
.attr('stroke', "black")
.attr('stroke-width', '1')
.attr("fill", function(d,i) { return "url(#pattern" + (i+1) +")"});
</script>
</html>
提前致谢。
您可以做的是也使用 D3 添加模式。 D3 实际上允许您向 DOM 添加任何类型的标签。因此,您可以进行第二次连接以添加模式。在下面的代码中,我只是“复制”了您的逻辑,但现在模式位于 g 元素中,并且模式位置位于条形图的左上角。当然你现在可以轻松调整这个了,希望对你有帮助!
<!doctype html>
<html>
<head>
<style>
</style>
<script src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<svg width="600" height="500"></svg>
<svg>
<rect x="0" y="0" width="100" height="100"
style="stroke: #000000; fill: url(#pattern1);" />
<rect x="100" y="0" width="100" height="100"
style="stroke: #000000; fill: url(#pattern2);" />
<rect x="200" y="0" width="100" height="100"
style="stroke: #000000; fill: url(#pattern3);" />
</svg>
</body>
<script>
var data = [{ year: '2001', value:10 },
{ year: '2002', value:30 },
{ year: '2003', value:20 },
]
var svg = d3.select("svg"),
margin = 200,
width = svg.attr("width") - margin,
height = svg.attr("height") - margin
var xScale = d3.scaleBand().range([0, width]).padding(0.4),
yScale = d3.scaleLinear().range([height, 0]);
var g = svg.append("g")
.attr("transform", "translate(" + 100 + "," + 100 + ")");
xScale.domain(data.map(function(d) { return d.year; }));
yScale.domain([0, d3.max(data, function(d) { return d.value; })]);
g.selectAll("defs.pattern")
.data(data)
.enter()
.append("defs").append("pattern")
.classed("pattern", true)
.attr("id", (_, i) => `pattern${i + 1}`)
.attr("x", (d) => xScale(d.year))
.attr("y", (d) => yScale(d.value))
.attr("width", 20)
.attr("height", 20)
.attr("patternUnits", "userSpaceOnUse")
.append("circle")
.attr("r", (_, i) => 3 * (i + 1))
.attr("cx", 10)
.attr("cy", 10)
.style("stroke", null)
.style("fill", "#0000ff")
g.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(xScale));
g.append("g")
.call(d3.axisLeft(yScale).tickFormat(function(d){
return d;
}).ticks(10));
g.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return xScale(d.year); })
.attr("y", function(d) { return yScale(d.value); })
.attr("width", xScale.bandwidth())
.attr("height", function(d) { return height - yScale(d.value); })
.attr('stroke', "black")
.attr('stroke-width', '1')
.attr("fill", function(d,i) { return "url(#pattern" + (i+1) +")"});
</script>
</html>
我创建了一个条形图并使用模式来填充它。对于每个图案,我设置 x=0 和 y=0,但我不知道这个 (0,0) 点在哪里,所以我不知道我的图案从哪里开始平铺。
我想将条形的左上角设置为每个条形图案的原点。我怎样才能做到这一点?
Diagram of the result I want
我的代码:
<!doctype html>
<html>
<head>
<style>
</style>
<script src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<svg width="600" height="500"></svg>
<svg>
<defs>
<pattern id="pattern1"
x="0" y="0" width="20" height="20"
patternUnits="userSpaceOnUse" >
<circle cx="10" cy="10" r="10" style="stroke: none; fill: #0000ff" />
</pattern>
</defs>
<defs>
<pattern id="pattern2"
x="0" y="0" width="20" height="20"
patternUnits="userSpaceOnUse" >
<circle cx="10" cy="10" r="5" style="stroke: none; fill: #0000ff" />
</pattern>
</defs>
<defs>
<pattern id="pattern3"
x="0" y="0" width="20" height="20"
patternUnits="userSpaceOnUse" >
<circle cx="10" cy="10" r="3" style="stroke: none; fill: #0000ff" />
</pattern>
</defs>
<rect x="0" y="0" width="100" height="100"
style="stroke: #000000; fill: url(#pattern1);" />
<rect x="100" y="0" width="100" height="100"
style="stroke: #000000; fill: url(#pattern2);" />
<rect x="200" y="0" width="100" height="100"
style="stroke: #000000; fill: url(#pattern3);" />
</svg>
</body>
<script>
var data = [{ year: '2001', value:10 },
{ year: '2002', value:30 },
{ year: '2003', value:20 },
]
var svg = d3.select("svg"),
margin = 200,
width = svg.attr("width") - margin,
height = svg.attr("height") - margin
var xScale = d3.scaleBand().range([0, width]).padding(0.4),
yScale = d3.scaleLinear().range([height, 0]);
var g = svg.append("g")
.attr("transform", "translate(" + 100 + "," + 100 + ")");
xScale.domain(data.map(function(d) { return d.year; }));
yScale.domain([0, d3.max(data, function(d) { return d.value; })]);
g.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(xScale));
g.append("g")
.call(d3.axisLeft(yScale).tickFormat(function(d){
return d;
}).ticks(10));
g.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return xScale(d.year); })
.attr("y", function(d) { return yScale(d.value); })
.attr("width", xScale.bandwidth())
.attr("height", function(d) { return height - yScale(d.value); })
.attr('stroke', "black")
.attr('stroke-width', '1')
.attr("fill", function(d,i) { return "url(#pattern" + (i+1) +")"});
</script>
</html>
提前致谢。
您可以做的是也使用 D3 添加模式。 D3 实际上允许您向 DOM 添加任何类型的标签。因此,您可以进行第二次连接以添加模式。在下面的代码中,我只是“复制”了您的逻辑,但现在模式位于 g 元素中,并且模式位置位于条形图的左上角。当然你现在可以轻松调整这个了,希望对你有帮助!
<!doctype html>
<html>
<head>
<style>
</style>
<script src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<svg width="600" height="500"></svg>
<svg>
<rect x="0" y="0" width="100" height="100"
style="stroke: #000000; fill: url(#pattern1);" />
<rect x="100" y="0" width="100" height="100"
style="stroke: #000000; fill: url(#pattern2);" />
<rect x="200" y="0" width="100" height="100"
style="stroke: #000000; fill: url(#pattern3);" />
</svg>
</body>
<script>
var data = [{ year: '2001', value:10 },
{ year: '2002', value:30 },
{ year: '2003', value:20 },
]
var svg = d3.select("svg"),
margin = 200,
width = svg.attr("width") - margin,
height = svg.attr("height") - margin
var xScale = d3.scaleBand().range([0, width]).padding(0.4),
yScale = d3.scaleLinear().range([height, 0]);
var g = svg.append("g")
.attr("transform", "translate(" + 100 + "," + 100 + ")");
xScale.domain(data.map(function(d) { return d.year; }));
yScale.domain([0, d3.max(data, function(d) { return d.value; })]);
g.selectAll("defs.pattern")
.data(data)
.enter()
.append("defs").append("pattern")
.classed("pattern", true)
.attr("id", (_, i) => `pattern${i + 1}`)
.attr("x", (d) => xScale(d.year))
.attr("y", (d) => yScale(d.value))
.attr("width", 20)
.attr("height", 20)
.attr("patternUnits", "userSpaceOnUse")
.append("circle")
.attr("r", (_, i) => 3 * (i + 1))
.attr("cx", 10)
.attr("cy", 10)
.style("stroke", null)
.style("fill", "#0000ff")
g.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(xScale));
g.append("g")
.call(d3.axisLeft(yScale).tickFormat(function(d){
return d;
}).ticks(10));
g.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return xScale(d.year); })
.attr("y", function(d) { return yScale(d.value); })
.attr("width", xScale.bandwidth())
.attr("height", function(d) { return height - yScale(d.value); })
.attr('stroke', "black")
.attr('stroke-width', '1')
.attr("fill", function(d,i) { return "url(#pattern" + (i+1) +")"});
</script>
</html>