OK, vì vậy tôi đã có một bước đi khác về vấn đề này - như đã đề cập trong câu trả lời trước đây của tôi , vấn đề lớn nhất bạn cần khắc phục là zoom d3 chỉ cho phép chia tỷ lệ đối xứng. Đây là điều đã được thảo luận rộng rãi và tôi tin rằng Mike Bostock đang giải quyết vấn đề này trong phiên bản tiếp theo.
Vì vậy, để khắc phục sự cố, bạn cần sử dụng nhiều hành vi thu phóng. Tôi đã tạo một biểu đồ có ba, một cho mỗi trục và một cho khu vực cốt truyện. Các hành vi thu phóng X & Y được sử dụng để chia tỷ lệ các trục. Bất cứ khi nào một sự kiện thu phóng được nâng lên bởi các hành vi thu phóng X & Y, các giá trị dịch của chúng sẽ được sao chép qua khu vực cốt truyện. Tương tự, khi một bản dịch xảy ra trên vùng vẽ, các thành phần x & y được sao chép sang các hành vi trục tương ứng.
Chia tỷ lệ trên khu vực cốt truyện phức tạp hơn một chút vì chúng ta cần duy trì tỷ lệ khung hình. Để đạt được điều này, tôi lưu trữ biến đổi thu phóng trước đó và sử dụng thang đo tỷ lệ để tìm ra một tỷ lệ phù hợp để áp dụng cho các hành vi thu phóng X & Y.
Để thuận tiện, tôi đã gói tất cả những thứ này vào một thành phần biểu đồ:
const interactiveChart = (xScale, yScale) => {
const zoom = d3.zoom();
const xZoom = d3.zoom();
const yZoom = d3.zoom();
const chart = fc.chartCartesian(xScale, yScale).decorate(sel => {
const plotAreaNode = sel.select(".plot-area").node();
const xAxisNode = sel.select(".x-axis").node();
const yAxisNode = sel.select(".y-axis").node();
const applyTransform = () => {
// apply the zoom transform from the x-scale
xScale.domain(
d3
.zoomTransform(xAxisNode)
.rescaleX(xScaleOriginal)
.domain()
);
// apply the zoom transform from the y-scale
yScale.domain(
d3
.zoomTransform(yAxisNode)
.rescaleY(yScaleOriginal)
.domain()
);
sel.node().requestRedraw();
};
zoom.on("zoom", () => {
// compute how much the user has zoomed since the last event
const factor = (plotAreaNode.__zoom.k - plotAreaNode.__zoomOld.k) / plotAreaNode.__zoomOld.k;
plotAreaNode.__zoomOld = plotAreaNode.__zoom;
// apply scale to the x & y axis, maintaining their aspect ratio
xAxisNode.__zoom.k = xAxisNode.__zoom.k * (1 + factor);
yAxisNode.__zoom.k = yAxisNode.__zoom.k * (1 + factor);
// apply transform
xAxisNode.__zoom.x = d3.zoomTransform(plotAreaNode).x;
yAxisNode.__zoom.y = d3.zoomTransform(plotAreaNode).y;
applyTransform();
});
xZoom.on("zoom", () => {
plotAreaNode.__zoom.x = d3.zoomTransform(xAxisNode).x;
applyTransform();
});
yZoom.on("zoom", () => {
plotAreaNode.__zoom.y = d3.zoomTransform(yAxisNode).y;
applyTransform();
});
sel
.enter()
.select(".plot-area")
.on("measure.range", () => {
xScaleOriginal.range([0, d3.event.detail.width]);
yScaleOriginal.range([d3.event.detail.height, 0]);
})
.call(zoom);
plotAreaNode.__zoomOld = plotAreaNode.__zoom;
// cannot use enter selection as this pulls data through
sel.selectAll(".y-axis").call(yZoom);
sel.selectAll(".x-axis").call(xZoom);
decorate(sel);
});
let xScaleOriginal = xScale.copy(),
yScaleOriginal = yScale.copy();
let decorate = () => {};
const instance = selection => chart(selection);
// property setters not show
return instance;
};
Đây là một cây bút với ví dụ hoạt động:
https://codepen.io/colineberhardt-the-bashful/pen/qBOEEGJ