Переход D3.js с холстом не является гладким при отображении
Я пытаюсь перейти между двумя состояниями карты d3.js, нарисованной на холсте, и столкнулся с небольшой проблемой: переходы не все такие гладкие. Это не похоже на переходы, которые у меня были с svg.
Я использую шаблон, описанный Ирен Рос в этом сообщении в блоге Bocoup.
Вот мой код, где я использую d3.timer и пользовательский элемент для создания абстракции данных для рисования на холсте. Как я могу улучшить производительность, чтобы каждая задержка перехода оживлялась плавно, а не резкими движениями?
Вопрос в этой строке: path(topojson.feature(data, data.objects.counties.geometries[i]));
Холст занимает слишком много времени, чтобы перерисовать все 2144 путей округа в каждом интервале d3.timer(). Таким образом, каждый интервал занимает около 1 секунды, тогда как для плавного перехода требуется 17 мс.
Мысли?
var width = 1600;
d3.json("/data/counties_merged.json", function(error, data) {
var projection = d3.geo.albersUsa();
var path = d3.geo.path().projection(projection);
var tracts = topojson.feature(data, data.objects.counties);
projection.scale(1).translate([0, 0]);
var b = path.bounds(tracts);
var whRatio = ((b[1][0] - b[0][0]) / (b[1][1] - b[0][1]));
var height = (width / 2) * whRatio;
var s = .98 / Math.max((b[1][0] - b[0][0]) / width, (b[1][1] - b[0][1]) / height),
t = [(width - s * (b[1][0] + b[0][0])) / 2, (height - s * (b[1][1] + b[0][1])) / 2];
projection.scale(s).translate(t);
var canvas = d3.select("#quintiles")
.append("canvas")
.attr("class", 'canvasarea');
var context = canvas.node().getContext("2d");
var ratio = window.devicePixelRatio || 1;
d3.select('.canvasarea')
.attr("width", width ).attr("height", height )
.style("width", ((width / ratio) ) + "px").style("height", ((height / ratio) ) + "px");
//context.scale(ratio, ratio);
var path = d3.geo.path()
.projection(projection)
.context(context);
if (error) throw error;
var strokeWidth = 0.4;
function drawCanvas(d,i) {
// clear canvas
context.fillStyle = "#fff";
context.rect(0,0,canvas.attr("width"),canvas.attr("height"));
context.fill();
// select our dummy nodes and draw the data to canvas.
var elements = dataContainer.selectAll("custom.county-path");
elements.each(function(d,i) {
context.beginPath();
context.strokeStyle = '#333';
context.fillStyle = d3.select(this).attr("fill");
context.lineWidth = strokeWidth;
path(topojson.feature(data, data.objects.counties.geometries[i]));
context.stroke();
context.fill();
context.restore();
})
}
// Create an in memory only element of type 'custom'
var detachedContainer = document.createElement("custom");
// Create a d3 selection for the detached container. We won't
// actually be attaching it to the DOM.
var dataContainer = d3.select(detachedContainer);
var paths;
function drawMap(cutoff) {
paths = dataContainer.selectAll("custom.county-path")
.data(data.objects.counties.geometries, function(d,i) { return d.id; });
paths.transition().duration(0).duration(5).delay(function(d,i) { return i * 0.25; })
.attr('fill',function(d,i) {
return (d.quintile !== undefined) ? (d.quintile < cutoff) ? '#8A85FF' : '#efefef' : '#efefef';
});
paths
.enter()
.append('custom')
.attr('class','county-path')
.attr('fill',function(d,i) {
return (d.quintile !== undefined) ? (d.quintile < cutoff) ? '#8A85FF' : '#efefef' : '#efefef';
});
}
d3.timer(drawCanvas);
drawMap(100);
drawMap(30);
});