响应d3刷牙

时间:2016-04-28 01:04:55

标签: javascript d3.js responsive-design

我有一个基于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);
}

1 个答案:

答案 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();


}