ตกลงดังนั้นฉันได้ไปที่นี้อีก - ตามที่กล่าวไว้ในคำตอบก่อนหน้าของฉันปัญหาที่ใหญ่ที่สุดที่คุณต้องเอาชนะคือ d3-zoom เท่านั้นอนุญาตให้ปรับขนาดสมมาตร นี่คือสิ่งที่มีการพูดคุยกันอย่างกว้างขวางและฉันเชื่อว่า Mike Bostock กำลังพูดถึงเรื่องนี้ในรุ่นถัดไป
ดังนั้นเพื่อที่จะเอาชนะปัญหานี้คุณต้องใช้พฤติกรรมการซูมหลายครั้ง ฉันได้สร้างแผนภูมิที่มีสามหนึ่งสำหรับแต่ละแกนและอีกหนึ่งสำหรับพื้นที่พล็อต พฤติกรรมการซูม X & Y ใช้เพื่อปรับขนาดของแกน เมื่อใดก็ตามที่เหตุการณ์การซูมถูกยกขึ้นโดยพฤติกรรมการซูม X & Y ค่าการแปลของพวกเขาจะถูกคัดลอกไปยังพื้นที่ลงจุด ในทำนองเดียวกันเมื่อการแปลเกิดขึ้นบนพื้นที่การลงจุดส่วนประกอบ x & y จะถูกคัดลอกไปยังพฤติกรรมของแกนตามลำดับ
การขยายพื้นที่แปลงมีความซับซ้อนเล็กน้อยเนื่องจากเราต้องรักษาอัตราส่วนภาพ เพื่อให้บรรลุเป้าหมายนี้ฉันจะเก็บการแปลงการซูมก่อนหน้านี้และใช้สเกลเดลต้าเพื่อคำนวณสเกลที่เหมาะสมเพื่อนำไปใช้กับพฤติกรรมการซูม X & Y
เพื่อความสะดวกฉันได้รวบรวมทั้งหมดนี้ไว้ในองค์ประกอบแผนภูมิ:
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;
};
นี่คือปากกาพร้อมตัวอย่างการทำงาน:
https://codepen.io/colineberhardt-the-bashful/pen/qBOEEGJ