Я использую D3 для создания диаграммы, ориентированной на время, которая использует масштабируемое поведение. Я следую шаблону, изложенному в статье Майка Бостока «На пути к многоразовым диаграммам», и, кроме того, пытается сделать отзывчивым.Отзывчивое поведение масштабирования D3
Многоразовый узор диаграммы позволяет мне просто вызвать мою диаграмму в setInterval, чтобы обработать отзывчивость. Некоторые значения, такие как ширина, обновляются каждый вызов, другие инкапсулируются в закрытие и устанавливаются только при создании начальной диаграммы. Одним из значений, требующих потенциального обновления каждого вызова, является диапазон шкалы.
Кроме того, в соответствии с https://github.com/mbostock/d3/wiki/Zoom-Behavior, изменяя домен или диапазон шкалы, которая автоматически корректируется с помощью масштабирования, необходимо (re) указать масштаб на поведение масштабирования (кроме того, масштаб масштабирования и значения перевода будут сбросить).
Однако следующий результат я получаю от respecifying шкалы на поведение масштабирования всякий раз, когда я изменить диапазон весов (а также обновление трансфокатора с последней шкалы и переводить значения):
function test(config) {
var aspectRatio = 10/3;
var margin = { top: 0, right: 0, bottom: 30, left: 0 };
var current = new Date();
var xScale = d3.time.scale().domain([d3.time.year.offset(current, -1), current]);
var xAxis = d3.svg.axis().scale(xScale).ticks(5);
var currentScale = 1;
var currentTranslate = [0, 0];
var zoom = d3.behavior.zoom().x(xScale).on('zoom', function() {
currentScale = d3.event.scale;
currentTranslate = d3.event.translate;
d3.select(this.parentNode.parentNode.parentNode).call(result);
});
var result = function(selection) {
selection.each(function(data) {
var outerWidth = $(this).width();
var outerHeight = outerWidth/aspectRatio;
var width = outerWidth - margin.left - margin.right;
var height = outerHeight - margin.top - margin.bottom;
xScale.range([0, width]);
zoom.x(xScale).scale(currentScale).translate(currentTranslate);
var svg = d3.select(this).selectAll('svg').data([data]);
var svgEnter = svg.enter().append('svg');
svg.attr('width', outerWidth).attr('height', outerHeight);
\t var gEnter = svgEnter.append('g');
\t var g = svg.select('g').attr('transform', 'translate(' + margin.left + ' ' + margin.top + ')');
gEnter.append('rect').attr('class', 'background').style('fill', '#F4F4F4').call(zoom);
g.select('rect.background').attr('width', width).attr('height', height);
\t \t var rectItem = g.selectAll('rect.item').data(function(d) {
return d;
});
\t \t rectItem.enter().append('rect').attr('class', 'item').style('fill', '#00F');
\t \t \t \t \t rectItem.attr('x', function(d) {
return xScale(d);
}).attr('width', xScale(d3.time.day.offset(xScale.invert(0), 7))).attr('height', height);
gEnter.append('g');
g.select('g').attr('transform', 'translate(0 ' + height + ')').call(xAxis);
});
};
return result;
}
setInterval(function() {
var selection = d3.select('#main').datum(d3.range(5).map(function() {
var current = new Date();
var mean = -d3.time.minute.range(current, d3.time.month.offset(current, 6)).length;
var deviation = d3.time.minute.range(current, d3.time.month.offset(current, 1)).length;
var random = d3.random.normal(mean, deviation);
return function() {
return d3.time.minute.offset(current, random());
};
}()));
var myTest = test();
return function() {
\t selection.call(myTest);
\t };
}(), 1000/60);
<div id="main"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
я могу получить очень близко, пытаясь минимально respecify масштаба на поведение масштабирования. Следующие работы, пока не изменять размер окна, то фокус зум не выстроены с помощью мыши больше:
http://jsfiddle.net/xf3fk8hu/1/
function test(config) {
var aspectRatio = 10/3;
var margin = { top: 0, right: 0, bottom: 30, left: 0 };
var current = new Date();
var xScale = d3.time.scale().domain([d3.time.year.offset(current, -1), current]);
var isZoomControllingScale = false;
var xAxis = d3.svg.axis().scale(xScale).ticks(5);
var currentScale = 1;
var currentTranslate = [0, 0];
var zoom = d3.behavior.zoom().on('zoom', function() {
currentScale = d3.event.scale;
currentTranslate = d3.event.translate;
d3.select(this.parentNode.parentNode.parentNode).call(result);
});
var result = function(selection) {
selection.each(function(data) {
var outerWidth = $(this).width();
var outerHeight = outerWidth/aspectRatio;
var width = outerWidth - margin.left - margin.right;
var height = outerHeight - margin.top - margin.bottom;
xScale.range([0, width]);
if(!isZoomControllingScale) {
isZoomControllingScale = true;
\t zoom.x(xScale).scale(currentScale).translate(currentTranslate);
}
var svg = d3.select(this).selectAll('svg').data([data]);
var svgEnter = svg.enter().append('svg');
svg.attr('width', outerWidth).attr('height', outerHeight);
\t var gEnter = svgEnter.append('g');
\t var g = svg.select('g').attr('transform', 'translate(' + margin.left + ' ' + margin.top + ')');
gEnter.append('rect').attr('class', 'background').style('fill', '#F4F4F4').call(zoom);
g.select('rect.background').attr('width', width).attr('height', height);
\t \t var rectItem = g.selectAll('rect.item').data(function(d) {
return d;
});
\t \t rectItem.enter().append('rect').attr('class', 'item').style('fill', '#00F');
\t \t \t \t \t rectItem.attr('x', function(d) {
return xScale(d);
}).attr('width', xScale(d3.time.day.offset(xScale.invert(0), 7))).attr('height', height);
gEnter.append('g');
g.select('g').attr('transform', 'translate(0 ' + height + ')').call(xAxis);
});
};
return result;
}
setInterval(function() {
var selection = d3.select('#main').datum(d3.range(5).map(function() {
var current = new Date();
var mean = -d3.time.minute.range(current, d3.time.month.offset(current, 6)).length;
var deviation = d3.time.minute.range(current, d3.time.month.offset(current, 1)).length;
var random = d3.random.normal(mean, deviation);
return function() {
return d3.time.minute.offset(current, random());
};
}()));
var myTest = test();
return function() {
\t selection.call(myTest);
\t };
}(), 1000/60);
<div id="main"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Как можно использовать поведение масштабирования в отзывчивым и многоразового использования?