D3 中動態計算 x 軸 y 軸的寬度以及偏移量
問題描述
在 D3.js 中經常會遇到這樣的情況:某一座標軸不能正確展示的情況。
如下圖所示:
造成這種情況的原因就是 y 軸上的數據過大,導致我們預留給 y 軸與左邊界的空間不足以展示 y 軸上所有的文字。
所以我們需要動態的計算 y 軸的寬度,通過 transform
屬性,將 y 軸上的文字完整的顯示出來。
原始代碼
先上剛開始的代碼:
// some code
initLine() {
const container = select(".bp-line")
this.width = parseInt(container.style("width"))
this.height = parseInt(container.style("height"))
const padding = {
top: 24,
right: 24,
bottom: 24,
left: 24
}
const svg = container.append('svg')
.attr("width", this.width)
.attr('height', this.height)
.style('background-color', "#fafbfc");
const xScale = scaleBand()
.domain(this.args.data.map((ele: any[]) => ele[0]))
.range([padding.left, this.width - padding.right ])
const xAxis = axisBottom(xScale)
const yScale = scaleLinear()
.domain([0, max(this.args.data.map((ele: any[]) => ele[1]))])
.range([this.height - padding.top - padding.bottom, 0]);
const yAxis = axisLeft(yScale)
svg.append('g')
.classed('x-axis', true)
.attr("transform", `translate(0,${this.height - padding.bottom})`)
.call(xAxis);
svg.append('g')
.classed('y-axis', true)
.call(yAxis)
}
// some code
通過代碼可以看出來,我們可以通過修改 y 軸的 transform
屬性,使其移動到正確的位置上,那麼這個屬性的值需要設置爲多少了?
移動 y 軸
這就需要我們進行計算,即座標軸距離容器左邊框有固定的 padding.left 同時再有座標軸的寬度的距離,就是一個非常合適的位置了。
這就需要我們去獲取 y 軸的寬度:
通過
// ...
// 動態獲取y座標軸的寬度
const yAxisWidth: number = svg.select('.y-axis').node().getBBox().width;
svg.select(".y-axis")
.attr("transform", `translate(${padding.left + yAxisWidth},${padding.top})`)
// ...
此時我們可以看到 y 軸已經移到了合適的位置:
但是 x 軸的範圍以及起始點有問題。我們這時候需要調整 x 軸的生成順序,放在計算完 y 軸的寬度之後。
移動 x 軸
最後的代碼是:
// some code
initLine() {
const container = select(".bp-line")
this.width = parseInt(container.style("width"))
this.height = parseInt(container.style("height"))
const padding = {
top: 24,
right: 24,
bottom: 24,
left: 24
}
const svg = container.append('svg')
.attr("width", this.width)
.attr('height', this.height)
.style('background-color', "#fafbfc");
const yScale = scaleLinear()
.domain([0, max(this.args.data.map((ele: any[]) => ele[1]))])
.range([this.height - padding.top - padding.bottom, 0]);
const yAxis = axisLeft(yScale)
svg.append('g')
.classed('y-axis', true)
.call(yAxis)
// 動態獲取y座標軸的寬度
const yAxisWidth: number = svg.select('.y-axis').node().getBBox().width;
svg.select(".y-axis")
.attr("transform", `translate(${padding.left + yAxisWidth},${padding.top})`)
// 最後繪製 x 座標軸,可以根據y軸的寬度動態計算 x軸所佔的寬度
const xScale = scaleBand()
.domain(this.args.data.map((ele: any[]) => ele[0]))
.range([padding.left, this.width - padding.right - yAxisWidth])
const xAxis = axisBottom(xScale)
svg.append('g')
.classed('x-axis', true)
.attr("transform", `translate(${yAxisWidth},${this.height - padding.bottom})`)
.call(xAxis);
}
// some code
結果
最後的結果可以看到 x 軸 y 軸都來到了合適的位置。