2017-07-22 4 views
0

Ich habe gelernt, d3 durch die Arbeit mit dem Brush & Zoom Beispiel, um eine benutzerdefinierte Zeitleiste zu machen. Ich möchte in der Lage sein, dem Benutzer zu ermöglichen, "Ansichten" der Timeline zu speichern: gezoomt und auf bestimmte Punkte verschoben, speichern Sie sie in JSON und dann später wiederherstellen."Pinsel & Zoom" speichern und wiederherstellen? (programmatischer Zoom)

Kann jemand mir einen Schubs in die richtige Richtung auf diese:

  1. Ich denke ich die aktuelle beide d3.event.selection und die aktuelle d3.event.transform
  2. serialisiert sie JSON
  3. Schreib speichern müssen eine Funktion, die die JSON übernimmt und die Auswahl und die Transformation neu erstellt.

Habe ich die Schritte richtig gemacht? Gibt es Arbeitsbeispiele (d3 v4), auf die Sie mich hinweisen können? Die meisten programmatischen Zoom-Beispiele & Tutorials, die ich gefunden habe, sind für frühere Versionen von d3 (pre v4).


Funktionen aus dem "Brush & Zoom" Beispiel der Interaktion behandeln:

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

Antwort

1

Es gibt tatsächlich ein Beispiel für einen programmatischen Zoom direkt im Code, den Sie betrachten :

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

Also, sagen wir "Ansicht" JSON in Bezug auf die zu Daten gezoomt gespeichert:

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

hier ein Lauf example:

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

Laden es einfach wäre.


<!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

Das genial Dank ist! Ich denke, das ist genug, um mich wieder in Bewegung zu bringen. –