修复可滚动热图 d3 中的 x 轴位置
Fix x-axis position in scrollable Heatmap d3
我创建了一个可滚动的热图,我想在滚动 y 轴时固定 x 轴。我检查了这里的一些帖子并尝试使解决方案工作,例如固定位置,但没有成功。
编辑:我试着用这个例子来解决它
但是现在我的x轴描述消失了,x轴放在了底部。
var width = 500,
height = 600,
margintop = 50,
marginbottom = 50,
marginright = 10,
marginleft = 50
d3.csv("https://raw.githubusercontent.com/Lea1216/d3/main/heatmap.csv", function(data) {
var svg = d3.select("#my_dataviz")
.append("div")
.classed("chart",true)
.append("svg")
.attr("width",width +marginleft + marginright)
.attr("height",height+margintop + marginbottom)
.append("g")
.attr("transform",
"translate(" + marginleft + "," + margintop + ")");
var axis = d3.select("#my_dataviz")
.append("svg")
.attr("width", width + marginleft +marginright)
.attr("height",40)
.append("g")
.attr("transform", "translate(" + marginleft + ", 0)");
var x_axis = d3.scaleBand()
.range([0, width])
.domain(data.map(function(d) {
return d.group;
}))
.padding(0.01);
axis.call(d3.axisTop(x_axis))
.selectAll("text")
.style("text-anchor", "end")
.style("position","fixed")
.attr("dx",15)
.attr("dy",5)
.attr("transform", "rotate(-65)");
var y_axis = d3.scaleBand()
.range([height, 0])
.domain(data.map(function(d) {
return d.activity;
}))
.padding(0.01);
svg.append("g")
.call(d3.axisLeft(y_axis))
.attr("class", "y_axis")
.selectAll("text")
.on("click", function(d) {
window.open(d.url, "_blank")
});
var myColor = d3.scaleLinear()
.range(["white", "#C37B89"])
.domain([1, 100])
svg.selectAll()
.data(data, function(d) {
return d.group + ':' + d.activity;
})
.enter()
.append("rect")
.attr("x", function(d) {
return x_axis(d.group)
})
.attr("y", function(d) {
return y_axis(d.activity)
})
.attr("width", x_axis.bandwidth())
.attr("height", y_axis.bandwidth())
.style("fill", function(d) {
return myColor(d.value)
})
.style("stroke-width", 1)
.style("stroke", "none")
})
.rect {
opacity: 0.8;
}
#my_dataviz {
width: 600px;
height: 500px;
overflow-y: scroll;
padding: 50px;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<div id="my_dataviz"></div>
对此有几种可能的解决方案。第一个是在同一层上绘制两个 SVG 元素,并在 X 轴元素上使用 position: fixed
。您可以看到块仍然显示在轴后面,但是您可以通过绘制 rect
轴 SVG 元素的总大小并给它 fill: white
:
来解决这个问题
var width = 500,
height = 600,
margintop = 50,
marginbottom = 50,
marginright = 10,
marginleft = 50
d3.csv("https://raw.githubusercontent.com/Lea1216/d3/main/heatmap.csv", function(data) {
// Add the axis *before* adding the SVG, because the order matters in HTML
var axis = d3.select("#my_dataviz")
.append("svg")
.attr("width", width + marginleft + marginright)
// Add 2 so you have a little bit of room left for the black bar
// i.e. margin top has to be less than total height!
.attr("height", margintop + 2)
.style("position", "fixed") // this makes the axis fixed
.append("g")
.attr("transform", "translate(" + marginleft + ", " + margintop + ")");
var svg = d3.select("#my_dataviz")
.append("svg")
.attr("width", width + marginleft + marginright)
.attr("height", height + margintop + marginbottom)
.append("g")
.attr("transform", "translate(" + marginleft + ", " + margintop + ")");
var x_axis = d3.scaleBand()
.range([0, width])
.domain(data.map(function(d) {
return d.group;
}))
.padding(0.01);
axis.call(d3.axisTop(x_axis))
.selectAll("text")
.style("text-anchor", "end")
.style("position", "fixed")
.attr("dx", 15)
.attr("dy", 5)
.attr("transform", "rotate(-65)");
var y_axis = d3.scaleBand()
.range([height, 0])
.domain(data.map(function(d) {
return d.activity;
}))
.padding(0.01);
svg.append("g")
.call(d3.axisLeft(y_axis))
.attr("class", "y_axis")
.selectAll("text")
.on("click", function(d) {
window.open(d.url, "_blank")
});
var myColor = d3.scaleLinear()
.range(["white", "#C37B89"])
.domain([1, 100])
svg.selectAll()
.data(data, function(d) {
return d.group + ':' + d.activity;
})
.enter()
.append("rect")
.attr("x", function(d) {
return x_axis(d.group)
})
.attr("y", function(d) {
return y_axis(d.activity)
})
.attr("width", x_axis.bandwidth())
.attr("height", y_axis.bandwidth())
.style("fill", function(d) {
return myColor(d.value)
})
.style("stroke-width", 1)
.style("stroke", "none")
})
.rect {
opacity: 0.8;
}
#my_dataviz {
border: solid 1px red;
width: 600px;
height: 300px;
overflow-y: scroll;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<div id="my_dataviz"></div>
第二个选项是将另一个 SVG 放在 div
中并滚动 div
而不是 SVG。然后,您确实需要使用 CSS 做更多事情,并且需要将一些 CSS 规则从 #my_dataviz
元素移动到 .chart
元素:
var width = 500,
height = 600,
margintop = 50,
marginbottom = 50,
marginright = 10,
marginleft = 50
d3.csv("https://raw.githubusercontent.com/Lea1216/d3/main/heatmap.csv", function(data) {
// Add the axis *before* adding the SVG, because the order matters in HTML
var axis = d3.select("#my_dataviz")
.append("svg")
.attr("width", width + marginleft + marginright)
// Add 2 so you have a little bit of room left for the black bar
// i.e. margin top has to be less than total height!
.attr("height", margintop + 1)
.append("g")
.attr("transform", "translate(" + marginleft + ", " + margintop + ")");
var svg = d3.select("#my_dataviz")
.append("div")
// Note the CSS rules for .chart
.attr("class", "chart")
.append("svg")
.attr("width", width + marginleft + marginright)
// No margin-top required here, because the other element already took care of it
.attr("height", height + marginbottom)
.append("g")
// Same, no margin-top
.attr("transform", "translate(" + marginleft + ", 0)");
var x_axis = d3.scaleBand()
.range([0, width])
.domain(data.map(function(d) {
return d.group;
}))
.padding(0.01);
axis.call(d3.axisTop(x_axis))
.selectAll("text")
.style("text-anchor", "end")
.style("position", "fixed")
.attr("dx", 15)
.attr("dy", 5)
.attr("transform", "rotate(-65)");
var y_axis = d3.scaleBand()
.range([height, 0])
.domain(data.map(function(d) {
return d.activity;
}))
.padding(0.01);
svg.append("g")
.call(d3.axisLeft(y_axis))
.attr("class", "y_axis")
.selectAll("text")
.on("click", function(d) {
window.open(d.url, "_blank")
});
var myColor = d3.scaleLinear()
.range(["white", "#C37B89"])
.domain([1, 100])
svg.selectAll()
.data(data, function(d) {
return d.group + ':' + d.activity;
})
.enter()
.append("rect")
.attr("x", function(d) {
return x_axis(d.group)
})
.attr("y", function(d) {
return y_axis(d.activity)
})
.attr("width", x_axis.bandwidth())
.attr("height", y_axis.bandwidth())
.style("fill", function(d) {
return myColor(d.value)
})
.style("stroke-width", 1)
.style("stroke", "none")
})
.rect {
opacity: 0.8;
}
#my_dataviz {
width: 600px;
border: solid 1px red;
}
/* To make sure there is no space between the DIV and the SVG */
#my_dataviz > * {
display: block;
}
.chart {
overflow-y: scroll;
max-height: 300px;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<div id="my_dataviz"></div>
我创建了一个可滚动的热图,我想在滚动 y 轴时固定 x 轴。我检查了这里的一些帖子并尝试使解决方案工作,例如固定位置,但没有成功。
编辑:我试着用这个例子来解决它
var width = 500,
height = 600,
margintop = 50,
marginbottom = 50,
marginright = 10,
marginleft = 50
d3.csv("https://raw.githubusercontent.com/Lea1216/d3/main/heatmap.csv", function(data) {
var svg = d3.select("#my_dataviz")
.append("div")
.classed("chart",true)
.append("svg")
.attr("width",width +marginleft + marginright)
.attr("height",height+margintop + marginbottom)
.append("g")
.attr("transform",
"translate(" + marginleft + "," + margintop + ")");
var axis = d3.select("#my_dataviz")
.append("svg")
.attr("width", width + marginleft +marginright)
.attr("height",40)
.append("g")
.attr("transform", "translate(" + marginleft + ", 0)");
var x_axis = d3.scaleBand()
.range([0, width])
.domain(data.map(function(d) {
return d.group;
}))
.padding(0.01);
axis.call(d3.axisTop(x_axis))
.selectAll("text")
.style("text-anchor", "end")
.style("position","fixed")
.attr("dx",15)
.attr("dy",5)
.attr("transform", "rotate(-65)");
var y_axis = d3.scaleBand()
.range([height, 0])
.domain(data.map(function(d) {
return d.activity;
}))
.padding(0.01);
svg.append("g")
.call(d3.axisLeft(y_axis))
.attr("class", "y_axis")
.selectAll("text")
.on("click", function(d) {
window.open(d.url, "_blank")
});
var myColor = d3.scaleLinear()
.range(["white", "#C37B89"])
.domain([1, 100])
svg.selectAll()
.data(data, function(d) {
return d.group + ':' + d.activity;
})
.enter()
.append("rect")
.attr("x", function(d) {
return x_axis(d.group)
})
.attr("y", function(d) {
return y_axis(d.activity)
})
.attr("width", x_axis.bandwidth())
.attr("height", y_axis.bandwidth())
.style("fill", function(d) {
return myColor(d.value)
})
.style("stroke-width", 1)
.style("stroke", "none")
})
.rect {
opacity: 0.8;
}
#my_dataviz {
width: 600px;
height: 500px;
overflow-y: scroll;
padding: 50px;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<div id="my_dataviz"></div>
对此有几种可能的解决方案。第一个是在同一层上绘制两个 SVG 元素,并在 X 轴元素上使用 position: fixed
。您可以看到块仍然显示在轴后面,但是您可以通过绘制 rect
轴 SVG 元素的总大小并给它 fill: white
:
var width = 500,
height = 600,
margintop = 50,
marginbottom = 50,
marginright = 10,
marginleft = 50
d3.csv("https://raw.githubusercontent.com/Lea1216/d3/main/heatmap.csv", function(data) {
// Add the axis *before* adding the SVG, because the order matters in HTML
var axis = d3.select("#my_dataviz")
.append("svg")
.attr("width", width + marginleft + marginright)
// Add 2 so you have a little bit of room left for the black bar
// i.e. margin top has to be less than total height!
.attr("height", margintop + 2)
.style("position", "fixed") // this makes the axis fixed
.append("g")
.attr("transform", "translate(" + marginleft + ", " + margintop + ")");
var svg = d3.select("#my_dataviz")
.append("svg")
.attr("width", width + marginleft + marginright)
.attr("height", height + margintop + marginbottom)
.append("g")
.attr("transform", "translate(" + marginleft + ", " + margintop + ")");
var x_axis = d3.scaleBand()
.range([0, width])
.domain(data.map(function(d) {
return d.group;
}))
.padding(0.01);
axis.call(d3.axisTop(x_axis))
.selectAll("text")
.style("text-anchor", "end")
.style("position", "fixed")
.attr("dx", 15)
.attr("dy", 5)
.attr("transform", "rotate(-65)");
var y_axis = d3.scaleBand()
.range([height, 0])
.domain(data.map(function(d) {
return d.activity;
}))
.padding(0.01);
svg.append("g")
.call(d3.axisLeft(y_axis))
.attr("class", "y_axis")
.selectAll("text")
.on("click", function(d) {
window.open(d.url, "_blank")
});
var myColor = d3.scaleLinear()
.range(["white", "#C37B89"])
.domain([1, 100])
svg.selectAll()
.data(data, function(d) {
return d.group + ':' + d.activity;
})
.enter()
.append("rect")
.attr("x", function(d) {
return x_axis(d.group)
})
.attr("y", function(d) {
return y_axis(d.activity)
})
.attr("width", x_axis.bandwidth())
.attr("height", y_axis.bandwidth())
.style("fill", function(d) {
return myColor(d.value)
})
.style("stroke-width", 1)
.style("stroke", "none")
})
.rect {
opacity: 0.8;
}
#my_dataviz {
border: solid 1px red;
width: 600px;
height: 300px;
overflow-y: scroll;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<div id="my_dataviz"></div>
第二个选项是将另一个 SVG 放在 div
中并滚动 div
而不是 SVG。然后,您确实需要使用 CSS 做更多事情,并且需要将一些 CSS 规则从 #my_dataviz
元素移动到 .chart
元素:
var width = 500,
height = 600,
margintop = 50,
marginbottom = 50,
marginright = 10,
marginleft = 50
d3.csv("https://raw.githubusercontent.com/Lea1216/d3/main/heatmap.csv", function(data) {
// Add the axis *before* adding the SVG, because the order matters in HTML
var axis = d3.select("#my_dataviz")
.append("svg")
.attr("width", width + marginleft + marginright)
// Add 2 so you have a little bit of room left for the black bar
// i.e. margin top has to be less than total height!
.attr("height", margintop + 1)
.append("g")
.attr("transform", "translate(" + marginleft + ", " + margintop + ")");
var svg = d3.select("#my_dataviz")
.append("div")
// Note the CSS rules for .chart
.attr("class", "chart")
.append("svg")
.attr("width", width + marginleft + marginright)
// No margin-top required here, because the other element already took care of it
.attr("height", height + marginbottom)
.append("g")
// Same, no margin-top
.attr("transform", "translate(" + marginleft + ", 0)");
var x_axis = d3.scaleBand()
.range([0, width])
.domain(data.map(function(d) {
return d.group;
}))
.padding(0.01);
axis.call(d3.axisTop(x_axis))
.selectAll("text")
.style("text-anchor", "end")
.style("position", "fixed")
.attr("dx", 15)
.attr("dy", 5)
.attr("transform", "rotate(-65)");
var y_axis = d3.scaleBand()
.range([height, 0])
.domain(data.map(function(d) {
return d.activity;
}))
.padding(0.01);
svg.append("g")
.call(d3.axisLeft(y_axis))
.attr("class", "y_axis")
.selectAll("text")
.on("click", function(d) {
window.open(d.url, "_blank")
});
var myColor = d3.scaleLinear()
.range(["white", "#C37B89"])
.domain([1, 100])
svg.selectAll()
.data(data, function(d) {
return d.group + ':' + d.activity;
})
.enter()
.append("rect")
.attr("x", function(d) {
return x_axis(d.group)
})
.attr("y", function(d) {
return y_axis(d.activity)
})
.attr("width", x_axis.bandwidth())
.attr("height", y_axis.bandwidth())
.style("fill", function(d) {
return myColor(d.value)
})
.style("stroke-width", 1)
.style("stroke", "none")
})
.rect {
opacity: 0.8;
}
#my_dataviz {
width: 600px;
border: solid 1px red;
}
/* To make sure there is no space between the DIV and the SVG */
#my_dataviz > * {
display: block;
}
.chart {
overflow-y: scroll;
max-height: 300px;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<div id="my_dataviz"></div>