問題:我正在嘗試創建一個可平移/可縮放的線性 X 軸,每個整數上都有刻度,從 0 到預定義的大數(比如說 1000,但可能更高)。顯然這不會全部適合螢屏并且可讀,所以我需要它離開螢屏并且可以平移。從 0 到 10 開始是可以接受的。到目前為止,我的解決方案存在許多問題,但第一個問題是,如果我放大,D3 會自動在小數位的整數之間添加刻度,以繼續在螢屏上顯示 10 個刻度。第二個是當我縮小時,范圍將顯示超過 1000。
快速說明:將顯示的資料無關緊要。無論 1000 上是否有資料點,軸都必須從 0 變為 1000,因此我無法根據我的資料集確定域。
我嘗試過的解決方案:
- .ticks()。這讓我可以指定我想要的刻度數。然而,這似乎將所有的刻度都放在了指定的初始范圍內。如果我將范圍的寬度增加到超過 svg 大小,它會分散刻度,但不是以任何可控的方式(據我所知)。此外,我遇到了平移和縮放的性能問題。我覺得這種行為很奇怪,因為如果我不指定刻度,它會產生一個無限的數字,我可以在沒有任何延遲的情況下平移。我假設出現延遲是因為它試圖立即渲染所有 1000 個刻度,并且默認的 d3.js 功能會在您滾動時動態渲染它們。這似乎是一個潛在的解決方案,但我不確定如何執行它。
- .tickValues()。我可以提供一個 0 到 1000 的陣列,這很有效,但表現出與 .ticks() 完全相同的滯后行為。當我縮小時,這也不會動態地將刻度組合成 10 或 100。
- .tickFormat()。我可以運行一個函式,以便將任何非整數轉換為空字串。但是,這仍然會留下刻度線。
以下是我使用最新版本的 D3.js(7.3) 的代碼的相關部分:
const height = 500
const width = 1200
const margin = {
top: 20,
right: 20,
bottom: 20,
left: 35
}
const innerWidth = width - margin.left - margin.right
const innerHeight = height - margin.top - margin.bottom
const xScale = d3.scaleLinear()
.domain([0, 10])
.range([0, innerWidth])
const svg = d3.select('svg')
.attr("width", width)
.attr("height", height)
svg.append('defs').append('clipPath')
.attr('id', 'clip')
.append('rect')
.attr('width', innerWidth)
.attr('height', innerHeight)
const zoom = d3.zoom()
.scaleExtent([1, 8])
.translateExtent([
[0, 0],
[xScale(upperBound), 0]
])
.on('zoom', zoomed)
const g = svg.append('g')
.attr('transform', `translate(${margin.left}, ${margin.top})`)
const xAxis = d3.axisBottom()
.scale(xScale)
const xAxisG = g.append('g')
.style('clip-path', 'url(#clip)')
.attr("class", "x-axis")
.call(xAxis)
.attr('transform', `translate(0, ${innerHeight})`)
svg.call(zoom)
function zoomed(event) {
const updateX = event.transform.rescaleX(xScale)
const zx = xAxis.scale(updateX)
xAxisG.call(zx)
}
uj5u.com熱心網友回復:
您可以簡單地選擇容器組本身中的刻度,而不是處理軸的方法,洗掉非整數:
xAxisG.call(zx)
.selectAll(".tick")
.filter(e => e % 1)
.remove();
這是您進行更改的代碼:
顯示代碼片段
const upperBound = 1000
const height = 100
const width = 600
const margin = {
top: 20,
right: 20,
bottom: 20,
left: 35
}
const innerWidth = width - margin.left - margin.right
const innerHeight = height - margin.top - margin.bottom
const xScale = d3.scaleLinear()
.domain([0, 10])
.range([0, innerWidth])
const svg = d3.select('svg')
.attr("width", width)
.attr("height", height)
svg.append('defs').append('clipPath')
.attr('id', 'clip')
.append('rect')
.attr('width', innerWidth)
.attr('height', innerHeight)
const zoom = d3.zoom()
.scaleExtent([1, 8])
.translateExtent([
[0, 0],
[xScale(upperBound), 0]
])
.on('zoom', zoomed)
const g = svg.append('g')
.attr('transform', `translate(${margin.left}, ${margin.top})`)
const xAxis = d3.axisBottom()
.scale(xScale)
.tickFormat(d => ~~d)
const xAxisG = g.append('g')
.style('clip-path', 'url(#clip)')
.attr("class", "x-axis")
.call(xAxis)
.attr('transform', `translate(0, ${innerHeight})`)
svg.call(zoom)
function zoomed(event) {
const updateX = event.transform.rescaleX(xScale)
const zx = xAxis.scale(updateX)
xAxisG.call(zx)
.selectAll(".tick")
.filter(e => e % 1)
.remove();
}
<script src="https://d3js.org/d3.v7.min.js"></script>
<svg></svg>
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/471083.html
標籤:javascript d3.js
下一篇:D3樹子節點的分頁
