【发布时间】:2016-06-27 17:43:42
【问题描述】:
我有一个项目需要独立缩放 3 个轴。我正在使用滚动条来完成此操作,但缩放发生时轴不会重绘。
此外,剪辑路径似乎没有按预期工作。
最后我也想在图表中添加平移功能,但我不知道从哪里开始。
提前感谢您的帮助。
// cases vs deaths of a disease over time
var data = [
{"year": "1960", "cases":"887", "deaths": "199"},
{"year": "1965", "cases":"218", "deaths": "55"},
{"year": "1993", "cases":"37046", "deaths": "931"},
{"year": "1994", "cases":"38735", "deaths": "118"},
{"year": "1995", "cases":"19903", "deaths": "624"},
{"year": "1997", "cases":"4170", "deaths": "125"},
{"year": "1998", "cases":"10000", "deaths": "0"}
];
data.forEach(function (d) {
d.year = d3.time.format("%Y").parse(d.year.toString());
d.cases = +d.cases;
d.deaths = +d.deaths;
});
var margin = { top: 30, right: 40, bottom: 30, left: 50 },
width = 500 - margin.left - margin.right,
height = 270 - margin.top - margin.bottom;
var xScale = d3.time.scale()
.domain(d3.extent(data, function (d) { return d.year; }))
.range([0, width]);
var yScaleLeft = d3.scale.linear()
.domain([0, d3.max(data, function (d) { return d.cases; })])
.range([height, 0]);
var yScaleRight = d3.scale.linear()
.domain([0, d3.max(data, function (d) { return d.deaths; })])
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom").ticks(5);
var yAxisLeft = d3.svg.axis()
.scale(yScaleLeft)
.orient("left").ticks(5);
var yAxisRight = d3.svg.axis()
.scale(yScaleRight)
.orient("right").ticks(5);
var lineCases = d3.svg.line()
.x(function (d) { return xScale(d.year); })
.y(function (d) { return yScaleLeft(d.cases); });
var lineDeaths = d3.svg.line()
.x(function (d) { return xScale(d.year); })
.y(function (d) { return yScaleRight(d.deaths); });
var svg = d3.select("#chart").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 + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis yleft")
.call(yAxisLeft);
svg.append("g")
.attr("class", "y axis yright")
.call(yAxisRight)
.attr('transform', 'translate(' + width + ',0)');
svg.append("path")
.datum(data)
.attr("class", "line lineLeft")
.style("stroke", "red")
.attr("d", lineCases(data))
.attr("clip", "url(#clip)");
svg.append("path")
.datum(data)
.attr("class", "line lineRight")
.attr("d", lineDeaths(data))
.attr("clip", "url(#clip)");
svg.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
$("#slider-x").slider({
orientation: "horizontal",
range: "min",
min: 1000,
max: 10000, // make max be (maxDate-minDate).Days*1000, so you can zoom to one day
value: 1000,
slide: function( event, ui ) {
zoomXWithSlider(ui.value/1000);
}
});
$( "#slider-y-left" ).slider({
orientation: "vertical",
range: "min",
min: 1000,
max: 10000,
value: 1000,
slide: function( event, ui ) {
zoomLeftWithSlider(ui.value/1000);
}
});
$("#slider-y-right").slider({
orientation: "vertical",
range: "min",
min: 1000,
max: 10000,
value: 1000,
slide: function( event, ui ) {
zoomRightWithSlider(ui.value/1000);
}
});
function zoomXWithSlider(scale) {
// Note: works only on the <g> element and not on the <svg> element
// which is a common mistake
svg.selectAll("path.line").attr("transform", "scale("+scale+", 1)");
svg.select(".x.axis").call(xAxis);
}
function zoomLeftWithSlider(scale) {
svg.select("path.line.lineLeft").attr("transform", "scale(1, "+scale+")");
svg.select(".y.axis.yleft").call(yAxisLeft);
}
function zoomRightWithSlider(scale) {
svg.select("path.line.lineRight").attr("transform", "scale(1, "+scale+")");
svg.select(".y.axis.yright").call(yAxisRight);
}
【问题讨论】:
-
有很多问题。我现在无法写出完整的答案。首先,当您对滑块更改做出反应并重绘轴时,您还必须修改轴所基于的比例,否则它们只会重绘相同的东西(如您所见)。例如,在 X 上,您可能会在重绘轴之前执行
xScale.range([0, width*scale])之类的操作。您可能需要重构一些东西,以便当滑块值发生变化时,您只捕获新的比例值,然后重新绘制全部或大部分图表,以避免代码重复。 -
一旦您开始平移,您还需要修改受影响范围的第一个元素(上面的
0),这是重构事物的进一步原因。 -
clipPath 无法正常工作的原因有多种。首先,
clipPath应该是<defs>部分的子项。而不是clip属性,您需要指定clip-path(如.attr("clip-path", "url(#clip)");)。但是仍然存在一个问题,通过在拖动滑块时缩放<path>,clipPath 也被隐式缩放,这意味着它不会继续基于恒定的图表宽度进行裁剪。为了明白我的意思,我特意将蒙版的宽度设置为width/2,以裁剪图表的一半。当您滑动 x 滑块时,看看它是如何增长的:jsfiddle.net/tvvcbrob -
我已经通过更新比例域然后重绘适当的元素来进行缩放。现在我需要实现平移和剪辑路径。 jsfiddle.net/0t19wq20
标签: d3.js svg slider zooming pan