2017-07-22 98 views
0

我一直在學習d3通過使用Brush & Zoom示例來製作自定義時間線。我希望能夠允許用戶保存時間表的「視圖」:縮放和平移到特定點,將它們保存到JSON,然後再恢復它們。保存和恢復「畫筆和縮放」? (程序縮放)

誰能給我這個在正確的方向輕推:

  1. 我想我需要保存兩個當前d3.event.selection和當前d3.event.transform
  2. 他們序列化JSON
  3. 寫一個函數將採取JSON並重新創建選擇和變換。

我有權利嗎?有沒有可以指點我的工作(d3 v4)例子?我發現的大多數編程縮放示例&教程都適用於早期版本的d3(pre v4)。從「刷&變焦」例如


功能,這處理交互:

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.select(".area").attr("d", area); 
    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; // ignore zoom-by-brush 
    var t = d3.event.transform; 
    x.domain(t.rescaleX(x2).domain()); 
    focus.select(".area").attr("d", area); 
    focus.select(".axis--x").call(xAxis); 
    context.select(".brush").call(brush.move, x.range().map(t.invertX, t)); 
} 

enter image description here

回答

1

實際上,有一個綱領性的變焦就在你正在尋找的代碼示例:

svg.select(".zoom").call(zoom.transform, d3.zoomIdentity 
    .scale(width/(s[1] - s[0])) 
    .translate(-s[0], 0)); 

所以,說我們存儲在我們的 「視圖」 JSON放大到日期的術語:

["2003-06-12T19:24:00.000Z","2006-05-20T19:24:00.000Z"] 

加載它只會是:

d3.json("viewData.json", function(error, data) { 
    var d = data.map(function(d){ 
    return new Date(d); 
    }) 
    svg.select(".zoom") 
    .transition() 
    .call(zoom.transform, d3.zoomIdentity 
     .scale(width/(x(d[1]) - x(d[0]))) 
     .translate(-x(d[0]), 0) 
    ); 
}); 

這裏是一個正在運行的example


<!DOCTYPE html> 
 
<meta charset="utf-8"> 
 
<style> 
 

 
.area { 
 
    fill: steelblue; 
 
    clip-path: url(#clip); 
 
} 
 

 
.zoom { 
 
    cursor: move; 
 
    fill: none; 
 
    pointer-events: all; 
 
} 
 

 
</style> 
 
<svg width="700" height="500"></svg> 
 
<script src="https://d3js.org/d3.v4.min.js"></script> 
 
<script> 
 

 
var svg = d3.select("svg"), 
 
    margin = {top: 20, right: 20, bottom: 110, left: 40}, 
 
    margin2 = {top: 430, right: 20, bottom: 30, left: 40}, 
 
    width = +svg.attr("width") - margin.left - margin.right, 
 
    height = +svg.attr("height") - margin.top - margin.bottom, 
 
    height2 = +svg.attr("height") - margin2.top - margin2.bottom; 
 

 
var parseDate = d3.timeParse("%b %Y"); 
 

 
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]); 
 

 
var xAxis = d3.axisBottom(x), 
 
    xAxis2 = d3.axisBottom(x2), 
 
    yAxis = d3.axisLeft(y); 
 

 
var brush = d3.brushX() 
 
    .extent([[0, 0], [width, height2]]) 
 
    .on("brush end", brushed); 
 

 
var zoom = d3.zoom() 
 
    .scaleExtent([1, Infinity]) 
 
    .translateExtent([[0, 0], [width, height]]) 
 
    .extent([[0, 0], [width, height]]) 
 
    .on("zoom", zoomed); 
 

 
var area = d3.area() 
 
    .curve(d3.curveMonotoneX) 
 
    .x(function(d) { return x(d.date); }) 
 
    .y0(height) 
 
    .y1(function(d) { return y(d.price); }); 
 

 
var area2 = d3.area() 
 
    .curve(d3.curveMonotoneX) 
 
    .x(function(d) { return x2(d.date); }) 
 
    .y0(height2) 
 
    .y1(function(d) { return y2(d.price); }); 
 

 
svg.append("defs").append("clipPath") 
 
    .attr("id", "clip") 
 
    .append("rect") 
 
    .attr("width", width) 
 
    .attr("height", height); 
 

 
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.json("https://jsonblob.com/api/8737d329-6f32-11e7-9e0d-efd5dcec6244", function(error, data) { 
 
    if (error) throw error; 
 
    
 
    data.forEach(type); 
 

 
    x.domain(d3.extent(data, function(d) { return d.date; })); 
 
    y.domain([0, d3.max(data, function(d) { return d.price; })]); 
 
    x2.domain(x.domain()); 
 
    y2.domain(y.domain()); 
 

 
    focus.append("path") 
 
     .datum(data) 
 
     .attr("class", "area") 
 
     .attr("d", area); 
 

 
    focus.append("g") 
 
     .attr("class", "axis axis--x") 
 
     .attr("transform", "translate(0," + height + ")") 
 
     .call(xAxis); 
 

 
    focus.append("g") 
 
     .attr("class", "axis axis--y") 
 
     .call(yAxis); 
 

 
    context.append("path") 
 
     .datum(data) 
 
     .attr("class", "area") 
 
     .attr("d", area2); 
 

 
    context.append("g") 
 
     .attr("class", "axis axis--x") 
 
     .attr("transform", "translate(0," + height2 + ")") 
 
     .call(xAxis2); 
 

 
    context.append("g") 
 
     .attr("class", "brush") 
 
     .call(brush) 
 
     .call(brush.move, x.range()); 
 

 
    svg.append("rect") 
 
     .attr("class", "zoom") 
 
     .attr("width", width) 
 
     .attr("height", height) 
 
     .attr("transform", "translate(" + margin.left + "," + margin.top + ")") 
 
     .call(zoom); 
 
}); 
 

 
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.select(".area").attr("d", area); 
 
    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; // ignore zoom-by-brush 
 
    var t = d3.event.transform; 
 
    x.domain(t.rescaleX(x2).domain()); 
 
    focus.select(".area").attr("d", area); 
 
    focus.select(".axis--x").call(xAxis); 
 
    context.select(".brush").call(brush.move, x.range().map(t.invertX, t)); 
 
} 
 

 
function type(d) { 
 
    d.date = new Date(d.date); 
 
    d.price = +d.price; 
 
    return d; 
 
} 
 

 
d3.select('body') 
 
    .append('button') 
 
    .style('margin', '20px') 
 
    .text('Load View') 
 
    .on('click', function(){ 
 
    d3.json("https://jsonblob.com/api/b580e2b9-6f32-11e7-9e0d-97f11fab6446", function(error, data) { 
 
     var d = data.map(function(d){ 
 
     return new Date(d); 
 
     }) 
 
     svg.select(".zoom").transition().call(zoom.transform, d3.zoomIdentity 
 
     .scale(width/(x(d[1]) - x(d[0]))) 
 
     .translate(-x(d[0]), 0)); 
 
    }); 
 
    }) 
 

 

 

 
</script>

+0

這真棒的感謝!我認爲這足以讓我再次移動。 –