OK, jadi saya sudah mencoba lagi - seperti yang disebutkan dalam jawaban saya sebelumnya , masalah terbesar yang perlu Anda atasi adalah bahwa d3-zoom hanya memungkinkan penskalaan simetris. Ini adalah sesuatu yang telah dibahas secara luas , dan saya percaya Mike Bostock sedang membahas ini di rilis berikutnya.
Jadi, untuk mengatasi masalah ini, Anda perlu menggunakan beberapa perilaku zoom. Saya telah membuat bagan yang memiliki tiga, satu untuk setiap sumbu dan satu untuk area plot. Perilaku pembesaran X & Y digunakan untuk menskalakan sumbu. Setiap kali acara zoom dinaikkan oleh perilaku zoom X & Y, nilai terjemahannya disalin ke area plot. Demikian juga, ketika terjemahan terjadi pada area plot, komponen x & y disalin ke perilaku sumbu masing-masing.
Penskalaan pada area plot sedikit lebih rumit karena kita perlu mempertahankan aspek rasio. Untuk mencapai ini, saya menyimpan transformasi zoom sebelumnya dan menggunakan skala delta untuk menentukan skala yang sesuai untuk diterapkan pada perilaku zoom X & Y.
Untuk kenyamanan, saya telah membungkus semua ini menjadi komponen bagan:
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;
};
Ini pulpen dengan contoh kerja:
https://codepen.io/colineberhardt-the-bashful/pen/qBOEEGJ