我有一個帶縮放功能的條形圖。問題是,縮放實際上并沒有居中。如果我將游標放在條形圖上并縮放,則游標下方的條形圖會移開而不是停留在那里,但是,如果我設定MARGIN.LEFT= 0,則問題將得到糾正,并且無論我將游標放在哪個條形上,當我縮放時,欄會停留在那里,就在下方。誰能幫我解決這個問題?
此處的作業代碼: https ://codesandbox.io/s/d3-zoom-not-centered-sfziyk
D3 代碼:
const MARGIN = {
LEFT: 60,
RIGHT: 40,
TOP: 10,
BOTTOM: 130
};
// total width incl margin
const VIEWPORT_WIDTH = 1140;
// total height incl margin
const VIEWPORT_HEIGHT = 400;
const WIDTH = VIEWPORT_WIDTH - MARGIN.LEFT - MARGIN.RIGHT;
const HEIGHT = VIEWPORT_HEIGHT - MARGIN.TOP - MARGIN.BOTTOM;
const svg = d3
.select(".chart-container")
.append("svg")
.attr("width", WIDTH MARGIN.LEFT MARGIN.RIGHT)
.attr("height", HEIGHT MARGIN.TOP MARGIN.BOTTOM);
const g = svg
.append("g")
.attr("transform", `translate(${MARGIN.LEFT}, ${MARGIN.TOP})`);
g.append("text")
.attr("class", "x axis-label")
.attr("x", WIDTH / 2)
.attr("y", HEIGHT 110)
.attr("font-size", "20px")
.attr("text-anchor", "middle")
.text("Month");
g.append("text")
.attr("class", "y axis-label")
.attr("x", -(HEIGHT / 2))
.attr("y", -60)
.attr("font-size", "20px")
.attr("text-anchor", "middle")
.attr("transform", "rotate(-90)")
.text("");
const zoom = d3.zoom().scaleExtent([0.5, 10]).on("zoom", zoomed);
svg.call(zoom);
function zoomed(event) {
x.range([0, WIDTH].map((d) => event.transform.applyX(d)));
barsGroup
.selectAll("rect.profit")
.attr("x", (d) => x(d.month))
.attr("width", 0.5 * x.bandwidth());
barsGroup
.selectAll("rect.revenue")
.attr("x", (d) => x(d.month) 0.5 * x.bandwidth())
.attr("width", 0.5 * x.bandwidth());
xAxisGroup.call(xAxisCall);
}
const x = d3.scaleBand().range([0, WIDTH]).paddingInner(0.3).paddingOuter(0.2);
const y = d3.scaleLinear().range([HEIGHT, 0]);
const xAxisGroup = g
.append("g")
.attr("class", "x axis")
.attr("transform", `translate(0, ${HEIGHT})`);
const yAxisGroup = g.append("g").attr("class", "y axis");
const xAxisCall = d3.axisBottom(x);
const yAxisCall = d3
.axisLeft(y)
.ticks(3)
.tickFormat((d) => "$" d);
const defs = svg.append("defs");
const barsClipPath = defs
.append("clipPath")
.attr("id", "bars-clip-path")
.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", WIDTH)
.attr("height", 400);
const barsGroup = g.append("g");
const zoomGroup = barsGroup.append("g");
barsGroup.attr("class", "bars");
zoomGroup.attr("class", "zoom");
barsGroup.attr("clip-path", "url(#bars-clip-path)");
xAxisGroup.attr("clip-path", "url(#bars-clip-path)");
d3.csv("data.csv").then((data) => {
data.forEach((d) => {
d.profit = Number(d.profit);
d.revenue = Number(d.revenue);
d.month = d.month;
});
var y0 = d3.max(data, (d) => d.profit);
var y1 = d3.max(data, (d) => d.revenue);
var maxdomain = y1;
if (y0 > y1) var maxdomain = y0;
x.domain(data.map((d) => d.month));
y.domain([0, maxdomain]);
xAxisGroup
.call(xAxisCall)
.selectAll("text")
.attr("y", "10")
.attr("x", "-5")
.attr("text-anchor", "end")
.attr("transform", "rotate(-40)");
yAxisGroup.call(yAxisCall);
const rects = zoomGroup.selectAll("rect").data(data);
rects.exit().remove();
rects
.attr("y", (d) => y(d.profit))
.attr("x", (d) => x(d.month))
.attr("width", 0.5 * x.bandwidth())
.attr("height", (d) => HEIGHT - y(d.profit));
rects
.enter()
.append("rect")
.attr("class", "profit")
.attr("y", (d) => y(d.profit))
.attr("x", (d) => x(d.month))
.attr("width", 0.5 * x.bandwidth())
.attr("height", (d) => HEIGHT - y(d.profit))
.attr("fill", "grey");
const rects_revenue = zoomGroup.selectAll("rect.revenue").data(data);
rects_revenue.exit().remove();
rects_revenue
.attr("y", (d) => y(d.revenue))
.attr("x", (d) => x(d.month))
.attr("width", 0.5 * x.bandwidth())
.attr("height", (d) => HEIGHT - y(d.revenue));
rects_revenue
.enter()
.append("rect")
.attr("class", "revenue")
.style("fill", "red")
.attr("y", (d) => y(d.revenue))
.attr("x", (d) => x(d.month) 0.5 * x.bandwidth())
.attr("width", 0.5 * x.bandwidth())
.attr("height", (d) => HEIGHT - y(d.revenue))
.attr("fill", "grey");
});
uj5u.com熱心網友回復:
當您call在zoomsvg 上時,所有縮放行為都與 svg 相關。
想象一下,您的 x 軸處于初始縮放級別,長度為 100,表示域 [0, 100]。所以 x 尺度有range([0, 100])和domain([0, 100])。添加左邊距 10。
如果您在 x=50 的軸中點按比例 2 縮放,您會期望在縮放后得到以下行為:
- 中點不動。
- 區間 [25, 75] 可見。
但是,由于在 svg 上呼叫了縮放,因此您必須考慮 10 的左邊距。縮放不會發生在中點,而是發生在 x = 10 50 = 60。因此轉換為 x -> x * k t 與 k = 2 和 t = -60。這導致
- x = 50 -> 2 * 50 - 60 = 40,
- x = 80 -> 2 * 80 - 60 = 100,
- x = 30 -> 2 * 30 - 60 = 0。
縮放后可見區間 [30, 80] 且點 x = 50 向左移動。
這就是你在圖表中觀察到的。
為了獲得預期的行為,您可以做兩件事:
一種。按照條形圖示例,x 刻度的范圍不是從 0 開始,而是從左邊距開始。g由 和 翻譯的margin.left,這里margin.top也省略了。相反,軸的范圍直接包含邊距。
灣。向 svg添加一個rect與fill: none; pointer-events: all;圖表大小相同的 svg,不帶邊距。然后呼叫該zoom矩形上的 ,如本例中所做的那樣。
請注意,ObservableHQ 上的所有新示例都遵循需要較少標記的模式“a”。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/430006.html
標籤:javascript d3.js 图表
上一篇:根據資料集改變顏色(d3)
下一篇:從一個Fragment移動到另一個Fragment時,SwipeRefreshLayout被復制到另一個Fragment
