2016-06-27 6 views
1

У меня есть проект, где мне нужно увеличить 3 оси независимо. Я использую полосы прокрутки для достижения этого, но оси не перерисовываются, когда происходит масштабирование.D3.js масштабирование с осью

Кроме того, путь клипа, похоже, не работает должным образом.

В конце концов, я хочу добавить функциональность панорамирования на диаграмму, но я не уверен, с чего начать.

http://jsfiddle.net/yo4mwLpj/

Заранее спасибо за помощь.

// cases vs deaths of a disease over time 
var data = [ 
{"year": "1960", "cases":"887", "deaths": "199"}, 
{"year": "1965", "cases":"218", "deaths": "55"}, 
{"year": "1993", "cases":"37046", "deaths": "931"}, 
{"year": "1994", "cases":"38735", "deaths": "118"}, 
{"year": "1995", "cases":"19903", "deaths": "624"}, 
{"year": "1997", "cases":"4170", "deaths": "125"}, 
{"year": "1998", "cases":"10000", "deaths": "0"} 
]; 
data.forEach(function (d) { 
    d.year = d3.time.format("%Y").parse(d.year.toString()); 
    d.cases = +d.cases; 
    d.deaths = +d.deaths; 
}); 

var margin = { top: 30, right: 40, bottom: 30, left: 50 }, 
    width = 500 - margin.left - margin.right, 
    height = 270 - margin.top - margin.bottom; 

var xScale = d3.time.scale() 
    .domain(d3.extent(data, function (d) { return d.year; })) 
    .range([0, width]); 

var yScaleLeft = d3.scale.linear() 
    .domain([0, d3.max(data, function (d) { return d.cases; })]) 
    .range([height, 0]); 

var yScaleRight = d3.scale.linear() 
    .domain([0, d3.max(data, function (d) { return d.deaths; })]) 
    .range([height, 0]); 

var xAxis = d3.svg.axis() 
    .scale(xScale) 
    .orient("bottom").ticks(5); 

var yAxisLeft = d3.svg.axis() 
    .scale(yScaleLeft) 
    .orient("left").ticks(5); 

var yAxisRight = d3.svg.axis() 
    .scale(yScaleRight) 
    .orient("right").ticks(5); 

var lineCases = d3.svg.line() 
    .x(function (d) { return xScale(d.year); }) 
    .y(function (d) { return yScaleLeft(d.cases); }); 

var lineDeaths = d3.svg.line() 
    .x(function (d) { return xScale(d.year); }) 
    .y(function (d) { return yScaleRight(d.deaths); }); 

var svg = d3.select("#chart").append("svg") 
    .attr("width", width + margin.left + margin.right) 
    .attr("height", height + margin.top + margin.bottom) 
    .append("g") 
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); 

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

svg.append("g") 
    .attr("class", "y axis yleft") 
    .call(yAxisLeft); 

svg.append("g") 
    .attr("class", "y axis yright") 
    .call(yAxisRight) 
    .attr('transform', 'translate(' + width + ',0)'); 

svg.append("path") 
    .datum(data) 
    .attr("class", "line lineLeft") 
    .style("stroke", "red") 
    .attr("d", lineCases(data)) 
    .attr("clip", "url(#clip)"); 

svg.append("path") 
    .datum(data) 
    .attr("class", "line lineRight") 
    .attr("d", lineDeaths(data)) 
    .attr("clip", "url(#clip)"); 

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

$("#slider-x").slider({ 
    orientation: "horizontal", 
    range: "min", 
    min: 1000, 
    max: 10000, // make max be (maxDate-minDate).Days*1000, so you can zoom to one day 
    value: 1000, 
    slide: function(event, ui) { 
     zoomXWithSlider(ui.value/1000); 
    } 
}); 

$("#slider-y-left").slider({ 
    orientation: "vertical", 
    range: "min", 
    min: 1000, 
    max: 10000, 
    value: 1000, 
    slide: function(event, ui) { 
     zoomLeftWithSlider(ui.value/1000); 
    } 
}); 

$("#slider-y-right").slider({ 
    orientation: "vertical", 
    range: "min", 
    min: 1000, 
    max: 10000, 
    value: 1000, 
    slide: function(event, ui) { 
     zoomRightWithSlider(ui.value/1000); 
    } 
}); 

function zoomXWithSlider(scale) { 
    // Note: works only on the <g> element and not on the <svg> element 
    // which is a common mistake 
    svg.selectAll("path.line").attr("transform", "scale("+scale+", 1)"); 
    svg.select(".x.axis").call(xAxis); 
} 

function zoomLeftWithSlider(scale) { 
    svg.select("path.line.lineLeft").attr("transform", "scale(1, "+scale+")"); 
    svg.select(".y.axis.yleft").call(yAxisLeft); 
} 

function zoomRightWithSlider(scale) { 
    svg.select("path.line.lineRight").attr("transform", "scale(1, "+scale+")"); 
    svg.select(".y.axis.yright").call(yAxisRight); 
} 
+0

Есть много проблем. Больше, чем я могу сейчас войти, чтобы написать полный ответ. Во-первых, когда вы реагируете на ползунок, меняете и перерисовываете оси, вы также должны изменять масштаб, на котором основаны оси, иначе они просто перерисовывают одно и то же (как вы видите). Например, на X вы можете сделать что-то вроде 'xScale.range ([0, width * scale])' перед перерисованием оси. Возможно, вам захочется реорганизовать такие вещи, чтобы при изменении значения ползунка вы записывали только новое значение шкалы, а затем перерисовывали всю или большую часть диаграммы, чтобы избежать повторения кода. – meetamit

+0

После того, как вы перейдете в панорамирование, вам также понадобится изменить первый элемент ('0', выше) затронутого диапазона, что является еще одной причиной для реорганизации объектов. – meetamit

+0

Существует несколько причин, по которым clipPath не работает. Во-первых, 'clipPath' должен быть дочерним элементом раздела' '. И вместо атрибута 'clip' вам нужно указать' clip-path' (как в '.attr (" clip-path "," url (#clip) ");'). Но по-прежнему существует проблема, которая, масштабируя '' при перемещении слайдера, также неявно масштабируется клиппат, а это означает, что он не продолжает обрезать на основе постоянной ширины диаграммы. Чтобы понять, что я имею в виду, я намеренно устанавливаю ширину маски 'width/2', чтобы обрезать половину графика. Посмотрите, как он растет при слайдере x: http://jsfiddle.net/tvvcbrob/ – meetamit

ответ

1

http://jsfiddle.net/8oo3ocfs/

var zoom = d3.behavior.zoom() //zoomYAxis 
    .x(xScale) 
    .y(yScaleLeft) 
    .on("zoom", function(){ 
     // don't let double-click or scroll wheel do anything 
     if (d3.event.sourceEvent == null || d3.event.sourceEvent.type == "wheel"){ 
     zoom.scale(previousScale); 
     zoom.translate(previousTranslate); 
     zoomRight.scale(previousScale); 
     zoomRight.translate(previousTranslate); 
     return; 
     } 

     // set previous scale for future use 
     previousScale = zoom.scale(); 
     previousTranslate = zoom.translate(); 

     //zoom.translate(panLimit()); 
     //zoomRight.translate(zoom.translate()); 

     // update the right side scale 
     zoomRight.scale(previousScale); 
     zoomRight.translate(previousTranslate); 

     // redraw lines 
     svg.select("path.line.lineLeft").attr("d", lineCases(data)); 
     svg.select("path.line.lineRight").attr("d", lineDeaths(data)); 

     // redraw axes 
     svg.select(".x.axis").call(xAxis); 
     svg.select(".y.axis.yleft").call(yAxisLeft); 
     svg.select(".y.axis.yright").call(yAxisRight); 
    }); 

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

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