我有一个基于Mike Bostock的'Focus + Context via brushing'的d3时间表,我正在努力做出回应。
我已经能够实现这一目标,但是我正在努力解决这个问题。作为一种解决方法,我尝试将其作为上下文的新宽度,但它的行为非常不稳定。我尝试过的其他所有内容似乎都没有效果 - 矩形区域不会改变宽度。
我需要一种方法来查找范围rect的x和宽度,并在调整大小时将它们应用到我的x-scale(名为xContext)。它有一个“工作”版本here,完整代码如下。调整大小功能是最底层的。
非常感谢提前。
var marginTimeline = {top: 0, right: 18, bottom: 260, left: 0},
marginContext = {top: 400, right: 18, bottom: 80, left: 0},
w = parseInt(d3.select("#chart").style("width")) - marginTimeline.left - marginTimeline.right,
hTimeline = parseInt(d3.select("#chart").style("height")) - marginTimeline.top - marginTimeline.bottom,
hContext = parseInt(d3.select("#chart").style("height")) - marginContext.top - marginContext.bottom;
//Height of the bars drawn. Context bars are half this.
var barHeight = hTimeline * 0.04;
var formatDate = d3.time.format("%Y%m%d"),
parseDate = formatDate.parse;
var xTimeline = d3.time.scale().range([0, w]),
xContext = d3.time.scale().range([0, w]),
yTimeline = d3.scale.linear().domain([0, 6]).range([hTimeline, 0]).nice(),
yContext = d3.scale.linear().range([hContext, 0]);
var thous = d3.format(",");
var displayDate = d3.time.format("%d %b %Y");
var displayMonthYear = d3.time.format("%b %Y");
var displayYear = d3.time.format("%Y");
var xAxisTimeline = d3.svg.axis().scale(xTimeline).orient("bottom"),
xAxisContext = d3.svg.axis().scale(xContext).orient("bottom"),
yAxisTimeline = d3.svg.axis().scale(yTimeline).orient("left").outerTickSize(0).ticks(0),
yAxisContext = d3.svg.axis().scale(yContext).orient("left").outerTickSize(0).ticks(0);
var svg = d3.select("#chart")
.attr("width", w + marginTimeline.left + marginTimeline.right)
.attr("height", hTimeline + marginTimeline.top + marginTimeline.bottom)
.append("g");
svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", w)
.attr("height", hTimeline);
var opTimeline = svg.append("g")
.attr("class", "timeline")
.attr("width", w)
.attr("height", hTimeline)
.attr("transform", "translate(10,0)");
var opContext = svg.append("g")
.attr("class", "context")
.attr("transform", "translate(10," + marginContext.top + ")");
var brush = d3.svg.brush()
.x(xContext)
.extent([0, 1])
.on("brush", brushed);
queue()
.defer(d3.json, "http://pasi.com.au/omarpasha/api/get_category_posts/?slug=shows&include=title,url,content,custom_fields")
.defer(d3.json, "http://pasi.com.au/omarpasha/api/get_category_posts/?slug=timeline&include=title,url,content,custom_fields")
.await(ready);
function ready(error, shows, history) {
shows.posts.forEach(function(d) {
d.id = d.id;
d.title = d.title;
d.showpage = d.url;
d.startDate = parseDate(d.custom_fields.starting_date[0]);
d.endDate = parseDate(d.custom_fields.finishing_date[0]);
})
history.posts.forEach(function(d) {
d.id = d.id;
d.title = d.title;
d.startDate = parseDate(d.custom_fields.starting_date[0]);
d.endDate = parseDate(d.custom_fields.finishing_date[0]);
d.line = d.custom_fields.line;
d.dateFormat = d.custom_fields.date_format;
});
var minDateShows = d3.min(shows.posts.map(function(d) { return d.startDate; }));
var minDateHistory = d3.min(history.posts.map(function(d) { return d.startDate; }));
var minDate = (minDateShows < minDateHistory ? minDateShows : minDateHistory);
var leftDate = new Date(minDate.getTime());
leftDate.setDate(leftDate.getDate()-40);
var maxDateShows = d3.max(shows.posts.map(function(d) { return d.endDate; }));
var maxDateHistory = d3.max(history.posts.map(function(d) { return d.endDate; }));
var maxDate = (maxDateShows > maxDateHistory ? maxDateShows : maxDateHistory);
var rightDate = new Date(maxDate.getTime());
rightDate.setDate(rightDate.getDate()+1400);
xTimeline.domain([leftDate, rightDate]);
xContext.domain(xTimeline.domain());
yContext.domain(yTimeline.domain());
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset(function(d) { if (xTimeline(d.endDate) > 800) { return [-10, 8] } else { return [-10, -8] } })
.direction(function(d) { if (xTimeline(d.endDate) > 800) { return 'nw' } else { return 'ne' } })
.html(function(d) {
if (displayMonthYear(d.startDate) == displayMonthYear(d.endDate)) {
return d.title + "<br/><p class='yellow'>" + displayMonthYear(d.startDate) + "</p>"; }
else {
return d.title + "<br/><p class='yellow'>"+ displayMonthYear(d.startDate) + " to " + displayMonthYear(d.endDate) + "</p>"; }
});
var tip2 = d3.tip()
.attr('class', 'd3-tip')
.direction(function(d) { if (xTimeline(d.endDate) > 800) { return 'nw' } else { return 'ne' } })
.offset(function(d) {
if (xTimeline(d.endDate) > 800) {
return [-10, 8];
} else {
return [-10, -8];
}
})
.html(function(d) {
var toolTipContent = "";
if ((xTimeline(d.endDate) - xTimeline(d.startDate) == 0)) {
toolTipContent = getToolTipContent(d, true);
} else {
toolTipContent = getToolTipContent(d, false);
}
return toolTipContent;
});
function getToolTipContent(d, sameDates) {
var toolTipContent = d.title + "<br/><p class='yellow'>";
if (d.dateFormat == "Year only") {
toolTipContent += (sameDates)
? displayYear(d.startDate) + "</p>" + d.content
: displayYear(d.startDate) + " to " + displayYear(d.endDate);
} else if (d.dateFormat == "Month and year") {
toolTipContent += (sameDates)
? displayMonthYear(d.startDate) + "</p>" + d.content
: displayMonthYear(d.startDate) + " to " + displayMonthYear(d.endDate);
} else {
toolTipContent += (sameDates)
? displayDate(d.startDate) + "</p>" + d.content
: displayDate(d.startDate) + " to " + displayDate(d.endDate);
}
toolTipContent += "</p>" + d.content;
return toolTipContent;
}
svg.call(tip);
svg.call(tip2);
opTimeline.append("line")
.attr("class", "show show-line")
.attr("x1", 0)
.attr("x2", w)
.attr("y1", yTimeline(5))
.attr("y2", yTimeline(5));
opTimeline.append("line")
.attr("class", "ost ost-line")
.attr("x1", 0)
.attr("x2", w)
.attr("y1", yTimeline(3))
.attr("y2", yTimeline(3));
opTimeline.append("line")
.attr("class", "blackart blackart-line")
.attr("x1", 0)
.attr("x2", w)
.attr("y1", yTimeline(1))
.attr("y2", yTimeline(1));
opContext.append("line")
.attr("class", "context show context-show-line")
.attr("x1", 0)
.attr("x2", w)
.attr("y1", yContext(5))
.attr("y2", yContext(5));
opContext.append("line")
.attr("class", "context ost context-ost-line")
.attr("x1", 0)
.attr("x2", w)
.attr("y1", yContext(3))
.attr("y2", yContext(3));
opContext.append("line")
.attr("class", "context blackart context-blackart-line")
.attr("x1", 0)
.attr("x2", w)
.attr("y1", yContext(1))
.attr("y2", yContext(1));
opTimeline.append("text")
.attr("class", "show show-text")
.attr("x", 10)
.attr("y", yTimeline(5) + 26)
.text("Shows");
opTimeline.append("text")
.attr("class", "ost ost-text")
.attr("x", 10)
.attr("y", yTimeline(3) + 26)
.text("Ostrowsky Family");
opTimeline.append("text")
.attr("class", "blackart blackart-text")
.attr("x", 10)
.attr("y", yTimeline(1) + 26)
.text("Black Art");
svg.append("text")
.attr("class", "explanation")
.attr("x", 10)
.attr("y", 380)
.text("Move the handles below to adjust the time period");
opTimeline.append("g")
.selectAll("rect")
.data(shows.posts)
.enter()
.append("svg:a")
.attr("xlink:href", function(d){return d.showpage;})
.append("rect")
.attr("class", "event show-event show")
.attr("clip-path", "url(#clip)")
.attr("x", (function(d) { return xTimeline(d.startDate); }))
.attr("width", (function(d) { if ((xTimeline(d.endDate) - xTimeline(d.startDate) > 12)) {
return (xTimeline(d.endDate) - xTimeline(d.startDate));}
else {
return 12
} }))
.attr("y", yTimeline(5) - (barHeight * 0.5))
.attr("height", barHeight)
.attr("rx", 10)
.attr("ry", 10);
opTimeline.append("g")
.selectAll("rect")
.data(history.posts)
.enter()
.append("rect")
.attr("class", (function(d) { if (d.line == "Ostrowsky family") { return "event ost-event ost" } else { return "event blackart-event blackart" } }))
.attr("clip-path", "url(#clip)")
.attr("x", (function(d) { return xTimeline(d.startDate); }))
.attr("width", (function(d) { if ((xTimeline(d.endDate) - xTimeline(d.startDate) > 12)) {
return (xTimeline(d.endDate) - xTimeline(d.startDate));}
else {
return 12
} }))
.attr("y", (function(d) { if (d.line == "Ostrowsky family") { return yTimeline(3) - (barHeight * 0.5) } else { return yTimeline(1) - (barHeight * 0.5) } }))
.attr("height", barHeight)
.attr("rx", 10)
.attr("ry", 10);
opContext.append("g")
.selectAll("rect")
.data(shows.posts)
.enter()
.append("rect")
.attr("class", "event show-event show")
.attr("x", (function(d) { return xContext(d.startDate); }))
.attr("width", (function(d) { if ((xTimeline(d.endDate) - xTimeline(d.startDate) > 6)) {
return (xTimeline(d.endDate) - xTimeline(d.startDate));}
else {
return 6
} }))
.attr("y", yContext(5) - (barHeight * 0.25))
.attr("height", barHeight/2)
.attr("rx", 5)
.attr("ry", 5);
opContext.append("g")
.selectAll("rect")
.data(history.posts)
.enter()
.append("rect")
.attr("class", (function(d) { if (d.line == "Ostrowsky family") { return "event ost-event ost" } else { return "event blackart-event blackart" } }))
.attr("x", (function(d) { return xContext(d.startDate); }))
.attr("width", (function(d) { if ((xTimeline(d.endDate) - xTimeline(d.startDate) > 6)) {
return (xTimeline(d.endDate) - xTimeline(d.startDate));}
else {
return 6
} }))
.attr("y", (function(d) { if (d.line == "Ostrowsky family") { return yContext(3) - (barHeight * 0.25) } else { return yContext(1) - (barHeight * 0.25) } }))
.attr("height", barHeight/2)
.attr("rx", 5)
.attr("ry", 5);
opTimeline.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + hTimeline + ")")
.call(xAxisTimeline);
opContext.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + hContext + ")")
.call(xAxisContext);
var brushg = opContext.append("g")
.attr("class", "x brush")
.call(brush)
.selectAll("rect")
.attr("y", -6)
.attr("height", hContext + 7);
opContext.selectAll(".e")
.append("image")
.attr("xlink:href",'../wp-content/themes/omarpasha/img/right-handle.png')
.attr("width", 10)
.attr("height", 70)
.attr("y", -6);
opContext.selectAll(".w")
.append("image")
.attr("xlink:href",'../wp-content/themes/omarpasha/img/left-handle.png')
.attr("width", 10)
.attr("height", 70)
.attr("x", -10)
.attr("y", -6);
opTimeline.selectAll(".show-event")
.on('mouseover', tip.show)
.on('mouseout', tip.hide);
opTimeline.selectAll(".ost-event, .blackart-event")
.on('mouseover', tip2.show)
.on('mouseout', tip2.hide);
function resize() {
marginContext = {top: 400, right: 18, bottom: 80, left: 0},
w = parseInt(d3.select("#chart").style("width")) - marginTimeline.left - marginTimeline.right,
hTimeline = parseInt(d3.select("#chart").style("height")) - marginTimeline.top - marginTimeline.bottom,
hContext = parseInt(d3.select("#chart").style("height")) - marginContext.top - marginContext.bottom;
var barHeight = hTimeline * 0.04;
xTimeline.range([0, w]),
xContext.range([0, w]),
yTimeline.range([hTimeline, 0]).nice(),
yContext.range([hContext, 0]);
svg
.attr("width", w + marginTimeline.left + marginTimeline.right)
.attr("height", hTimeline + marginTimeline.top + marginTimeline.bottom);
svg.select("#clip rect")
.attr("width", w)
.attr("height", hTimeline);
d3.select(".background")
.attr("width", w);
opTimeline
.attr("width", w)
.attr("height", hTimeline)
.attr("transform", "translate(10,0)");
opContext
.attr("transform", "translate(10," + marginContext.top + ")");
opTimeline.select('.x.axis')
.attr("transform", "translate(0," + hTimeline + ")")
.call(xAxisTimeline);
opContext.select('.x.axis')
.attr("transform", "translate(0," + hContext + ")")
.call(xAxisContext);
opTimeline.select(".show-line")
.attr("x2", w);
opTimeline.select(".ost-line")
.attr("x2", w);
opTimeline.select(".blackart-line")
.attr("x2", w);
opContext.select(".context-show-line")
.attr("x2", w);
opContext.select(".context-ost-line")
.attr("x2", w);
opContext.select(".context-blackart-line")
.attr("x2", w);
opTimeline.selectAll(".event")
.attr("x", (function(d) { return xTimeline(d.startDate); }))
.attr("width", (function(d) { if ((xTimeline(d.endDate) - xTimeline(d.startDate) > 12)) {
return (xTimeline(d.endDate) - xTimeline(d.startDate));}
else {
return 12
} }));
opContext.selectAll(".event")
.attr("x", (function(d) { return xContext(d.startDate); }))
.attr("width", (function(d) { if ((xContext(d.endDate) - xContext(d.startDate) > 6)) {
return (xContext(d.endDate) - xContext(d.startDate));}
else {
return 6
} }));
brush
.x(xContext)
.extent([0, 1])
.on("brush", brushed);
}
d3.select(window).on('resize', resize);
resize();
};
function brushed() {
xTimeline.domain(brush.empty() ? xContext.domain() : brush.extent());
opTimeline.selectAll("rect").attr("x", (function(d) { return xTimeline(d.startDate); }))
.attr("width", (function(d) { if ((xTimeline(d.endDate) - xTimeline(d.startDate) > 12)) { return (xTimeline(d.endDate) - xTimeline(d.startDate));} else { return 12 } }));
opTimeline.select(".x.axis").call(xAxisTimeline);
}
答案 0 :(得分:1)
我在Stack Overflow之外有人为我排序。解决方案很简单 - 在调整大小函数开始时捕获画笔范围的状态。没有其他改变。所以resize函数现在看起来像这样(仍然相当冗长,但正在工作):
function resize() {
var extent = brush.extent();
w = parseInt(d3.select("#chart").style("width")) - marginTimeline.left - marginTimeline.right,
hTimeline = parseInt(d3.select("#chart").style("height")) - marginTimeline.top - marginTimeline.bottom;
var barHeight = hTimeline * 0.04;
xTimeline.range([0, w]),
xContext.range([0, w]),
yTimeline.range([hTimeline, 0]).nice(),
yContext.range([hContext, 0]);
svg
.attr("width", w + marginTimeline.left + marginTimeline.right);
svg.select("#clip rect")
.attr("width", w);
opTimeline
.attr("width", w)
.attr("transform", "translate(10,0)");
opContext
.attr("transform", "translate(10," + marginContext.top + ")");
opTimeline.select('.x.axis')
.attr("transform", "translate(0," + hTimeline + ")")
.call(xAxisTimeline);
opContext.select('.x.axis')
.attr("transform", "translate(0," + hContext + ")")
.call(xAxisContext);
opTimeline.select(".show-line")
.attr("x2", w);
opTimeline.select(".ost-line")
.attr("x2", w);
opTimeline.select(".blackart-line")
.attr("x2", w);
opContext.select(".context-show-line")
.attr("x2", w);
opContext.select(".context-ost-line")
.attr("x2", w);
opContext.select(".context-blackart-line")
.attr("x2", w);
opTimeline.selectAll(".event")
.attr("x", (function(d) { return xTimeline(d.startDate); }))
.attr("width", (function(d) { if ((xTimeline(d.endDate) - xTimeline(d.startDate) > 12)) {
return (xTimeline(d.endDate) - xTimeline(d.startDate));}
else {
return 12
} }));
opContext.selectAll(".event")
.attr("x", (function(d) { return xContext(d.startDate); }))
.attr("width", (function(d) { if ((xContext(d.endDate) - xContext(d.startDate) > 6)) {
return (xContext(d.endDate) - xContext(d.startDate));}
else {
return 6
} }));
brush.extent(extent);
// Now just call the methods to update the brush.
opContext.select("g.x.brush").call(brush);
brushed();
}