d3.js: lựa chọn đồng bộ trên nhiều biểu đồ
Làm cách nào để xử lý lựa chọn khi tôi muốn lưu trữ lựa chọn đồng bộ trên nhiều biểu đồ? Khi tôi thực hiện một lựa chọn, lựa chọn giống hệt nhau cũng sẽ được hiển thị trên các biểu đồ khác.
Tôi đã thêm cho bạn một ví dụ về jsfiddle được tạo trong dc.js.
Mã của tôi vào lúc này giống như sau:
var signalData = {
signal1: {
name: "signal1",
data: [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 1, 2, 3, 5, 4, 1, 4, 2, 9, 7, 5, 7, 4, 6],
},
signal2: {
name: "signal2",
data: [6, 4, 8, 5, 4, 8, 4, 3, 5, 4, 5, 8, 7, 2, 9, 5, 4, 1, 2, 6, 0, 5, 7, 1],
},
signal3: {
name: "signal3",
data: [9, 5, 12, 3, 8, 4, 8, 6, 3, 4, 7, 8, 5, 2, 1, 8, 6, 8, 5, 8, 4, 8, 5, 1],
},
}
var margin = {
top: 10,
right: 50,
bottom: 40,
left: 50
};
var width = window.innerWidth - margin.left - margin.right;
var height = 200 - margin.top - margin.bottom;
var xScale = d3
.scaleLinear()
.domain([0, d3.max(Object.keys(signalData), d => signalData[d].data.length)]) // input
.range([0, width]); // output
var brushXScale = d3
.scaleLinear()
.domain([0, d3.max(Object.keys(signalData), d => signalData[d].data.length)]) // input
.range([0, width]); // output
var brush = d3.brushX().extent([
[0, 0],
[width - margin.right, height],
]).on("brush", brushed);
function brushed(d) {
var selectionPx = d3.brushSelection(this); // === [lower, upper] in pixels
// transform from pixels to x-values
var selectionX = [xScale.invert(selectionPx[0]), xScale.invert(selectionPx[1])];
// set x scale domain, then redraw the lines
brushXScale.domain(selectionX);
for (var signal in signalData) {
updateChart(
signalData[signal].data,
signalData[signal].name
);
}
}
//Generate the brush focus chart
generateMinimap(signalData.signal1.data);
//Generate charts dynamically as often as i have signals
for (var signal in this.signalData) {
generateChart(
signalData[signal].data,
signalData[signal].name
);
}
// This function is for the one time preparations
function generateChart(data, name) {
var svg = d3
.select("#" + name)
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg
.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
svg.append("g").attr("class", "y axis");
svg
.append("path")
.attr("class", "line") // Assign a class for styling
.attr("fill", "none")
.attr("stroke", "blue");
updateChart(data, name);
}
// This function needs to be called to update the already prepared chart
function updateChart(data, name) {
var svg = d3.select("#" + name + " svg");
var yScale = d3
.scaleLinear()
.domain([0, d3.max(data)]) // input
.range([height, 0]); // output
var line = d3
.line()
.x((d, i) => brushXScale(i))
.y((d) => yScale(d));
console.log(line([1, 2, 3, 4]));
svg.select(".x.axis")
.call(d3.axisBottom(brushXScale));
svg.select(".y.axis")
.call(d3.axisLeft(yScale));
svg
.select(".line")
.datum(data) // 10. Binds data to the line
.attr("d", line) // 11. Calls the line generator
}
function generateMinimap(data) {
var yScale = d3
.scaleLinear()
.domain([0, d3.max(data)]) // input
.range([height, 0]); // output
var line = d3
.line()
.x((d, i) => xScale(i))
.y((d) => yScale(d));
var svg = d3
.select("#minimap")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.append("g").call(brush);
svg
.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(xScale)); // Create an axis component with d3.axisBottom
svg
.append("path")
.datum(data) // 10. Binds data to the line
.attr("class", "line") // Assign a class for styling
.attr("d", line) // 11. Calls the line generator
.attr("fill-opacity", "0.17")
.attr("fill", "blue")
.attr("stroke", "blue");
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div id="minimap"></div>
<!-- In the original project these divs are not
static and get generated with v-for as many times as
i have a signal in signalData -->
<div id="signal1"></div>
<div id="signal2"></div>
<div id="signal3"></div>
Điều quan trọng cần biết là các biểu đồ đang được hiển thị động và số lượng biểu đồ có thể nhiều hơn hoặc ít hơn!
Tôi đã cố gắng lấy dữ liệu ra khỏi lựa chọn và thêm nó vào những dữ liệu khác nhưng tôi không đi đến kết quả.
Trả lời
Dựa trên ví dụ này , bạn có thể gọi theo brushchương trình .
Bằng cách này, mọi trường hợp đều được đánh dấu giống nhau. Tôi đã tạo một bàn chải mới selectBrushgọi tất cả các hộp chứa bàn chải khác và áp dụng cùng một bàn chải ở đó.
var signalData = {
signal1: {
name: "signal1",
data: [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 1, 2, 3, 5, 4, 1, 4, 2, 9, 7, 5, 7, 4, 6],
},
signal2: {
name: "signal2",
data: [6, 4, 8, 5, 4, 8, 4, 3, 5, 4, 5, 8, 7, 2, 9, 5, 4, 1, 2, 6, 0, 5, 7, 1],
},
signal3: {
name: "signal3",
data: [9, 5, 12, 3, 8, 4, 8, 6, 3, 4, 7, 8, 5, 2, 1, 8, 6, 8, 5, 8, 4, 8, 5, 1],
},
};
var margin = {
top: 10,
right: 50,
bottom: 40,
left: 50,
};
var width = window.innerWidth - margin.left - margin.right;
var height = 200 - margin.top - margin.bottom;
var xScale = d3
.scaleLinear()
.domain([0, d3.max(Object.keys(signalData), d => signalData[d].data.length)]) // input
.range([0, width]); // output
var brushXScale = d3
.scaleLinear()
.domain([0, d3.max(Object.keys(signalData), d => signalData[d].data.length)]) // input
.range([0, width]); // output
var zoomBrush = d3.brushX()
.extent([
[0, 0],
[width - margin.right, height],
])
.on("brush", zoomBrushed);
var selectBrush = d3.brushX()
.extent([
[0, 0],
[width - margin.right, height],
])
.on("brush", selectBrushed);
function zoomBrushed() {
var selectionPx = d3.brushSelection(this); // === [lower, upper] in pixels
// transform from pixels to x-values
var selectionX = [xScale.invert(selectionPx[0]), xScale.invert(selectionPx[1])];
// set x scale domain, then redraw the lines
brushXScale.domain(selectionX);
for(var signal in signalData) {
updateChart(
signalData[signal].data,
signalData[signal].name,
);
}
}
function selectBrushed() {
var selectionPx = d3.brushSelection(this); // === [lower, upper] in pixels
selectBrush.on("brush", null);
// This is the starts-with selector (https://www.w3schools.com/cssref/sel_attr_begin.asp)
d3.selectAll("div[id^=signal] svg .brushcontainer")
.call(selectBrush.move, selectionPx);
selectBrush.on("brush", selectBrushed);
}
//Generate the brush focus chart
generateMinimap(signalData.signal1.data);
//Generate charts dynamically as often as i have signals
for(var signal in this.signalData) {
generateChart(
signalData[signal].data,
signalData[signal].name,
);
}
// This function is for the one time preparations
function generateChart(data, name) {
var svg = d3
.select("#" + name)
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg
.append("g")
.attr("class", "brushcontainer")
.call(selectBrush);
svg
.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")");
svg.append("g")
.attr("class", "y axis");
svg
.append("path")
.attr("class", "line") // Assign a class for styling
.attr("fill", "none")
.attr("stroke", "blue");
updateChart(data, name);
}
// This function needs to be called to update the already prepared chart
function updateChart(data, name) {
var svg = d3.select("#" + name + " svg");
var yScale = d3
.scaleLinear()
.domain([0, d3.max(data)]) // input
.range([height, 0]); // output
var line = d3
.line()
.x((d, i) => brushXScale(i))
.y((d) => yScale(d));
svg.select(".x.axis")
.call(d3.axisBottom(brushXScale));
svg.select(".y.axis")
.call(d3.axisLeft(yScale));
svg
.select(".line")
.datum(data) // 10. Binds data to the line
.attr("d", line); // 11. Calls the line generator
}
function generateMinimap(data) {
var yScale = d3
.scaleLinear()
.domain([0, d3.max(data)]) // input
.range([height, 0]); // output
var line = d3
.line()
.x((d, i) => xScale(i))
.y((d) => yScale(d));
var svg = d3
.select("#minimap")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.append("g")
.call(zoomBrush);
svg
.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(xScale)); // Create an axis component with d3.axisBottom
svg
.append("path")
.datum(data) // 10. Binds data to the line
.attr("class", "line") // Assign a class for styling
.attr("d", line) // 11. Calls the line generator
.attr("fill-opacity", "0.17")
.attr("fill", "blue")
.attr("stroke", "blue");
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div id="minimap"></div>
<!-- In the original project these divs are not
static and get generated with v-for as many times as
i have a signal in signalData -->
<div id="signal1"></div>
<div id="signal2"></div>
<div id="signal3"></div>