我尝试使用d3.js v4用画笔和缩放功能构建一个堆叠的条形图,我能够渲染图表以及画笔。但是,当尝试放大时,仅轴发生变化,实际图形保持不变。我在这里附上摘要。
参考:https://bl.ocks.org/mbostock/34f08d5e11952a80609169b7917d4172
谢谢您的帮助。
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.zoom {
cursor: move;
fill: none;
pointer-events: all;
}
.axis {
stroke-width: 0.5px;
stroke: #888;
font: 10px avenir next, sans-serif;
}
.axis > path {
stroke: #888;
}
</style>
<svg width="960" height="500"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var margin = {top: 20, right: 20, bottom: 90, left: 50},
margin2 = {top: 230, right: 20, bottom: 30, left: 50},
width = 960 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom,
height2 = 300 - margin2.top - margin2.bottom;
var parseTime = d3.timeParse("%Y-%m-%d");
var x = d3.scaleTime().range([0, width]),
x2 = d3.scaleTime().range([0, width]),
y = d3.scaleLinear().range([height, 0]),
y2 = d3.scaleLinear().range([height2, 0]);
z = d3.scaleOrdinal().range(["#a54300","#ec983d", "#ecc43d", "#f9ec86","#cbe989"]);
var xAxis = d3.axisBottom(x),
xAxis2 = d3.axisBottom(x2),
yAxis = d3.axisLeft(y);
var brush = d3.brushX()
.extent([[0, 0], [width, height2]])
.on("brush", brushed);
var zoom = d3.zoom()
.scaleExtent([1, Infinity])
.translateExtent([[0, 0], [width, height]])
.extent([[0, 0], [width, height]])
.on("zoom", zoomed);
var svg = d3.select("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
var focus = svg.append("g")
.attr("class", "focus")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var context = svg.append("g")
.attr("class", "context")
.attr("transform", "translate(" + margin2.left + "," + margin2.top + ")");
d3.csv("https://gist.githubusercontent.com/Udayshan07/320ea33bacc3e04f9bd77538007527a0/raw/06e65434349e63ed6cf85c4d3e9cb383e888010c/sp500.csv", function(d, i, columns) {
for (i = 1, t = 0; i < columns.length; ++i) t += d[columns[i]] = +d[columns[i]];
d.total = t;
return d;
}, function(error, data) {
if (error) throw error;
data.forEach(function(d) {
d.Week_Num = parseTime(d.Week_Num);
});
var xMin = d3.min(data, function(d) { return d.Week_Num; });
var yMax = Math.max(20, d3.max(data, function(d) { return d.total; }));
var keys = data.columns.slice(1);
var data = d3.stack().keys(keys)(data);
x.domain([xMin, new Date()]);
y.domain([0, yMax]);
x2.domain(x.domain());
y2.domain(y.domain())
z.domain(keys);
var messages = focus.append("g");
messages.selectAll("message")
.data(data)
.enter().append("g")
.attr("fill", function(d) { return z(d.key); })
.selectAll("rect")
.data(function(d) { return d; })
.enter().append("rect")
.attr("x", function(d) { return x(d.data.Week_Num); })
.attr("y", function(d) { return y(d[1]); })
.attr("height", function(d) { return y(d[0]) - y(d[1]); })
.attr("width", 15)
.on("mouseover", function() { tooltip.style("display", null); })
.on("mouseout", function() { tooltip.style("display", "none"); })
.on("mousemove", function(d) {
console.log(d);
var xPosition = d3.mouse(this)[0] - 5;
var yPosition = d3.mouse(this)[1] - 5;
tooltip.attr("transform", "translate(" + xPosition + "," + yPosition + ")");
tooltip.select("text").text(d[1]-d[0]);
});
focus.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(xAxis.ticks(10))
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
focus.append("g")
.attr("class", "axis axis--y")
.call(yAxis);
svg.append("rect")
.attr("class", "zoom")
.attr("width", width)
.attr("height", height)
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(zoom);
context.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height2 + ")")
.call(xAxis2)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", "rotate(-65)");
context.append("g")
.attr("class", "brush")
.call(brush)
.call(brush.move, x.range());
});
function brushed() {
//console.log('Brush 1');
if (d3.event.sourceEvent && d3.event.sourceEvent.type === "zoom") return; // ignore brush-by-zoom
// console.log('Brush 2');
var s = d3.event.selection || x2.range();
x.domain(s.map(x2.invert, x2));
focus.selectAll(".message")
.attr("x", function(d) { return x(d.Week_Num); })
.attr("y", function(d) { colsole.log("Brush" + y(d[1])); return y(d[1]); });
focus.select(".axis--x").call(xAxis);
svg.select(".zoom").call(zoom.transform, d3.zoomIdentity
.scale(width / (s[1] - s[0]))
.translate(-s[0], 0));
}
function zoomed() {
// console.log('Zoom 1');
if (d3.event.sourceEvent && d3.event.sourceEvent.type === "brush") return;
// ignore zoom-by-brush
// console.log('Zoom 2');
var t = d3.event.transform;
x.domain(t.rescaleX(x2).domain());
focus.selectAll(".message")
.attr("x", function(d) { return x(d.Week_Num); })
.attr("y", function(d) { colsole.log("Zoom" + y(d[1])); return y(d[1]);});
focus.select(".axis--x").call(xAxis);
context.select(".brush").call(brush.move, x.range().map(t.invertX, t));
}
var tooltip = svg.append("g")
.attr("class", "tooltip")
.style("display", "none");
tooltip.append("rect")
.attr("width", 60)
.attr("height", 20)
.attr("fill", "white")
.style("opacity", 0.5);
tooltip.append("text")
.attr("x", 30)
.attr("dy", "1.2em")
.style("text-anchor", "middle")
.attr("font-size", "12px")
.attr("font-weight", "bold");
</script>
答案 0 :(得分:0)
关于该问题,您有两个主要问题:
在缩放/拖动功能中:
focus.selectAll(".message")
.attr("x", function(d) { return x(d.Week_Num); })
.attr("y", function(d) { colsole.log("Brush" + y(d[1])); return y(d[1]); });
没有项目具有类message
,因此这是一个空选择-这就是为什么命令colsole.log
不会触发错误,也永远不会运行的原因。您可以只选择焦点选择中的所有rect
(或为每个矩形提供消息类别)。 此外,您无需重新定位y值,也无需重新缩放y值,因此它可以保持不变,我已在下面的代码段中将其删除了
一旦更改,我们就会遇到问题2。
rect
使用x属性时,使用的是x(d.data.Week_Num);
,但是在拖动/缩放功能中使用的是x(d.Week_Num);
,这很容易固定。这给了我们
var margin = {top: 20, right: 20, bottom: 90, left: 50},
margin2 = {top: 230, right: 20, bottom: 30, left: 50},
width = 960 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom,
height2 = 300 - margin2.top - margin2.bottom;
var parseTime = d3.timeParse("%Y-%m-%d");
var x = d3.scaleTime().range([0, width]),
x2 = d3.scaleTime().range([0, width]),
y = d3.scaleLinear().range([height, 0]),
y2 = d3.scaleLinear().range([height2, 0]);
z = d3.scaleOrdinal().range(["#a54300","#ec983d", "#ecc43d", "#f9ec86","#cbe989"]);
var xAxis = d3.axisBottom(x),
xAxis2 = d3.axisBottom(x2),
yAxis = d3.axisLeft(y);
var brush = d3.brushX()
.extent([[0, 0], [width, height2]])
.on("brush", brushed);
var zoom = d3.zoom()
.scaleExtent([1, Infinity])
.translateExtent([[0, 0], [width, height]])
.extent([[0, 0], [width, height]])
.on("zoom", zoomed);
var svg = d3.select("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
var focus = svg.append("g")
.attr("class", "focus")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var context = svg.append("g")
.attr("class", "context")
.attr("transform", "translate(" + margin2.left + "," + margin2.top + ")");
d3.csv("https://gist.githubusercontent.com/Udayshan07/320ea33bacc3e04f9bd77538007527a0/raw/06e65434349e63ed6cf85c4d3e9cb383e888010c/sp500.csv", function(d, i, columns) {
for (i = 1, t = 0; i < columns.length; ++i) t += d[columns[i]] = +d[columns[i]];
d.total = t;
return d;
}, function(error, data) {
if (error) throw error;
data.forEach(function(d) {
d.Week_Num = parseTime(d.Week_Num);
});
var xMin = d3.min(data, function(d) { return d.Week_Num; });
var yMax = Math.max(20, d3.max(data, function(d) { return d.total; }));
var keys = data.columns.slice(1);
var data = d3.stack().keys(keys)(data);
x.domain([xMin, new Date()]);
y.domain([0, yMax]);
x2.domain(x.domain());
y2.domain(y.domain())
z.domain(keys);
var messages = focus.append("g");
messages.selectAll("message")
.data(data)
.enter().append("g")
.attr("fill", function(d) { return z(d.key); })
.selectAll("rect")
.data(function(d) { return d; })
.enter().append("rect")
.attr("x", function(d) { return x(d.data.Week_Num); })
.attr("y", function(d) { return y(d[1]); })
.attr("height", function(d) { return y(d[0]) - y(d[1]); })
.attr("width", 15)
.on("mouseover", function() { tooltip.style("display", null); })
.on("mouseout", function() { tooltip.style("display", "none"); })
.on("mousemove", function(d) {
console.log(d);
var xPosition = d3.mouse(this)[0] - 5;
var yPosition = d3.mouse(this)[1] - 5;
tooltip.attr("transform", "translate(" + xPosition + "," + yPosition + ")");
tooltip.select("text").text(d[1]-d[0]);
});
focus.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(xAxis.ticks(10))
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
focus.append("g")
.attr("class", "axis axis--y")
.call(yAxis);
svg.append("rect")
.attr("class", "zoom")
.attr("width", width)
.attr("height", height)
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(zoom);
context.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height2 + ")")
.call(xAxis2)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", "rotate(-65)");
context.append("g")
.attr("class", "brush")
.call(brush)
.call(brush.move, x.range());
});
function brushed() {
if (d3.event.sourceEvent && d3.event.sourceEvent.type === "zoom") return; // ignore brush-by-zoom
var s = d3.event.selection || x2.range();
x.domain(s.map(x2.invert, x2));
focus.selectAll("rect")
.attr("x", function(d) { return x(d.data.Week_Num); })
focus.select(".axis--x").call(xAxis);
svg.select(".zoom").call(zoom.transform, d3.zoomIdentity
.scale(width / (s[1] - s[0]))
.translate(-s[0], 0));
}
function zoomed() {
if (d3.event.sourceEvent && d3.event.sourceEvent.type === "brush") return;
var t = d3.event.transform;
x.domain(t.rescaleX(x2).domain());
focus.selectAll("rect")
.attr("x", function(d) { return x(d.data.Week_Num); });
focus.select(".axis--x").call(xAxis);
context.select(".brush").call(brush.move, x.range().map(t.invertX, t));
}
var tooltip = svg.append("g")
.attr("class", "tooltip")
.style("display", "none");
tooltip.append("rect")
.attr("width", 60)
.attr("height", 20)
.attr("fill", "white")
.style("opacity", 0.5);
tooltip.append("text")
.attr("x", 30)
.attr("dy", "1.2em")
.style("text-anchor", "middle")
.attr("font-size", "12px")
.attr("font-weight", "bold");
.zoom {
cursor: move;
fill: none;
pointer-events: all;
}
.axis {
stroke-width: 0.5px;
stroke: #888;
font: 10px avenir next, sans-serif;
}
.axis > path {
stroke: #888;
}
<svg width="960" height="500"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
该问题并未解决对剪切路径的需求,因此我没有将其包含在答案中,但是关于该主题的问题很多,例如{{3} }。几天前。