Я бы подошел к такой проблеме: создайте ориентированный на силу макет, начиная с одного из уроков (возможно, this one, так как он создает что-то, что использует упаковку кругов для инициализации). Добавьте D3 в режим масштабирования.
var force = d3.layout.force()
// force layout settings
var zoom = d3.behavior.zoom()
// etc.
Пока что так хорошо. За исключением того, что силовой макет нравится болтаться вокруг [width/2, height/2]
, но он делает масштабирование проще, если вы находитесь в центре вокруг [0, 0]
. Боритесь с geometric zooming на некоторое время, пока не осознаете, что эта проблема действительно требует semantic zooming. Внедрение семантического масштабирования. Пойдите, выпейте кофе.
Выясните взаимосвязь между размерами ваших кругов и уровнем масштабирования, которые позволят вам рассказать, когда должен быть раскрыт следующий уровень. Что-то вроде этого:
// expand when this percent of the screen is covered
var coverageThreshold = 0.6;
// the circles should be scaled to this size
var maxRadius = 20;
// the size of the visualization
var width = 960;
// which means this is the magic scale factor
var scaleThreshold = maxRadius/(coverageThreshold * width)
// note: the above is probably wrong
Теперь создайте фильтр пространственных данных. По мере того, как вы уменьшаете масштаб изображения, вы в основном хотите скрыть любые точки данных, которые вышли из поля зрения, так что вы не тратите время на вычисление своего представления. Кроме того, выясните алгоритм, который определит, какой узел пользователь увеличивает. Это очень хорошо может использовать Voronoi tessalation. Узнайте больше, чем вы думали о геометрии.
Еще одна математическая вещь, которую нам нужно разработать. Мы будем иметь дочерние узлы вместо родительского узла, поэтому нам нужно масштабировать их размер на основе общего размера родителя. Это будет раздражать и требует некоторой настройки, чтобы получить право, если вы не знаете правильный алгоритм ... Я этого не делаю.
// size of the parent node
var parentRadius = someNumberPossiblyCalculated;
// area of the parent node
var parentArea = 2 * Math.PI * parentRadius;
// percent of the the parent's area that will be covered by children
// (here be dragons)
var childrenCoverageRatio = 0.8;
// total area covered by children
var childrenArea = parentArea * childrenCoverageArea;
// the total of the radiuses of the children
var childTotal = parent.children
.map(radiusFn)
.reduce(function(a, b) { return a + b; });
// the child radius function
// use this to generate the child elements with d3
// (optimize that divide in production!)
var childRadius = function(d) {
return maxRadius * radiusFn(d)/childTotal;
};
// note: the above is probably wrong
Хорошо, теперь у нас есть кусочки на месте, чтобы сделать волшебный соус. В обработчике zoom
отметьте d3.event.scale
против вашей контрольной точки. Если пользователь увеличено мимо него, выполните следующие действия очень быстро:
- скрыть родительские элементы, которые вне экрана
- удалить родительский узел, который масштабируется в
- добавить дочерние узлы от этого родителя к компоновке на х и у расположения родителя
- явно запустить
force.tick()
несколько раз, чтобы дети раздвигают чуток
- потенциально использовать макет круг-упаковки, чтобы сделать этот процесс чистки
Итак, теперь у нас есть небольшая небольшая схема с масштабированием. Когда вы увеличите масштаб изображения, вы нажмете некоторый порог, который, мы надеемся, будет автоматически вычисляться кодом визуализации. Когда вы это делаете, узел, который вы увеличиваете, «взрывается» во все его составные узлы.
Теперь выясните, как структурировать свой код, чтобы вы могли «перезагрузить» вещи, чтобы вы могли продолжать масштабирование и повторить это. Это может быть рекурсивным, но может быть проще просто сжать шкалы на несколько порядков и одновременно расширить элементы SVG с помощью обратного фактора.
zoom zoom. Прежде всего, вам понадобится отдельный порог масштабирования для обратного процесса, эффект гистерезиса в элементе управления, который поможет предотвратить скачкообразную визуализацию, если кто-то вернется на колесико. Вы увеличиваете масштаб и расширяетесь, тогда вам нужно немного увеличить масштаб, прежде чем он снова сработает.
Хорошо, когда вы нажмете порог уменьшения изображения, вы просто бросаете дочерние элементы и добавляете родителя обратно в центр тяжести местоположений детей.
var parent.x = d3.mean(parent.children, function(d) { return d.x; });
var parent.y = d3.mean(parent.children, function(d) { return d.y; });
Кроме того, как вы сигналить вне начала показывать те узлы, которые вы спрятали в то время как масштабирование.
Как @Lars упоминалось, это, вероятно, займет некоторое время.
Да, это возможно. Вам нужно будет объединить силу и компоновку упаковки. [Этот учебник] (http://www.delimited.io/blog/2013/12/19/force-bubble-charts-in-d3) не совсем то, но может помочь. –
Спасибо, @LarsKotthoff, но, может быть, есть примеры? В каждом примере все данные загружаются сразу. Мне нужно загрузить его динамически с определенным уровнем масштабирования ... – Andron
Я не знаю ни одного примера, который специально делает то, что вы ищете. –