2016-12-30 3 views
0

Я пытаюсь получить прокручиваемую линейную диаграмму D3.JS для автоматической корректировки осей на основе текущего вида пользователя.Обновить оси на прокручиваемой линейной диаграмме D3.JS на основе пользовательского вида

Чтобы привести пример, предполагаемое поведение можно увидеть в Google Finance.

В первом графике, вы можете видеть цены достиг пика на отметке 5485:

enter image description here

На втором графике, я прокручивается вперед, и вы можете видеть, что диаграмма автоматически повторно масштабируется размещения нового пика в 5510:

enter image description here

Обратите внимание, что это поведение отличается от просто сделать диаграмму отзывчивой, которая может быть легко достигнута, помещая эн график шин, в том числе данные за пределами зрения пользователя, в реагирующей контейнере, например:

.svg-container { 
    display: inline-block; 
    position: relative; 
    width: 100%; 
    padding-bottom: 65%; 
    vertical-align: top; 
    overflow: hidden; 
} 

Для того, чтобы решить эту проблему, я бы нужно различать целиком истории цен и в сегменте пользователь в данный момент просмотра, затем установите диапазон оси y. Как я могу это достичь?

ответ

1

Не уверен, что я понимаю вопрос, но похоже, что вы просто хотите масштабировать ось y по мере изменения выбранного диапазона данных. Сформировав this classic example, я изменил его так, чтобы по мере того, как вы меняете или изменяете изменения домена оси y в соответствии с текущим выбором. Код ключа это в brushed обратного вызова:

// set new y domain based on selection 
y.domain([0, d3.max(data, function(d) { 
    if (d.x < x.domain()[0] || d.x > x.domain()[1]) return 0; 
    else return d.y; 
})]); 
// redraw y axis 
focus.select(".axis--y").call(yAxis); 

Полный пример:

<!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="960" 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 x = d3.scaleLinear().range([0, width]), 
 
    x2 = d3.scaleLinear().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.x); 
 
    }) 
 
    .y0(height) 
 
    .y1(function(d) { 
 
     return y(d.y); 
 
    }); 
 

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

 
    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 + ")"); 
 

 
    var data = []; 
 
    for (var i = 0; i < 100; i++) { 
 
    data.push({ 
 
     x: i, 
 
     y: i > 50 ? Math.random() * 100 : Math.random() * 50 
 
    }); 
 
    } 
 

 
    x.domain(d3.extent(data, function(d) { 
 
    return d.x; 
 
    })); 
 
    y.domain([0, d3.max(data, function(d) { 
 
    return d.y; 
 
    })]); 
 
    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); 
 

 
    y.domain([0, d3.max(data, function(d) { 
 
     if (d.x < x.domain()[0] || d.x > x.domain()[1]) return 0; 
 
     else return d.y; 
 
    })]); 
 
    focus.select(".axis--y").call(yAxis); 
 

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

 
    y.domain([0, d3.max(data, function(d) { 
 
     if (d.x < x.domain()[0] || d.x > x.domain()[1]) return 0; 
 
     else return d.y; 
 
    })]); 
 
    focus.select(".axis--y").call(yAxis); 
 

 
    context.select(".brush").call(brush.move, x.range().map(t.invertX, t)); 
 
    } 
 
</script>

+0

Да, это то, что я пытаюсь сделать. Я позже работал с тем же примером в вашей ссылке, но не смог заставить его правильно рисовать ось y, когда вы щёлкаете. Благодарю. – Martin

Смежные вопросы