D3.js 中動態計算 x 軸 y 軸的寬度以及偏移量

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 軸已經移到了合適的位置:
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 軸都來到了合適的位置。
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章