2012-09-07 31 views
6

मैंने माइक Bostock के नोड-लिंक पेड़ के आधार पर D3.js में एक वृक्ष बनाया। मेरे पास समस्या है और मैं माइक के पेड़ में भी देखता हूं कि टेक्स्ट लेबल कुछ जगह छोड़ने के लिए लिंक का विस्तार करने के बजाय पर्याप्त स्थान नहीं होने पर सर्कल नोड्स को ओवरलैप/अंडरलैप करता है।ट्रीमैप पर टेक्स्ट तत्वों के ओवरलैपिंग से कैसे बचें जब D3.js में बच्चे तत्व खोले जाते हैं?

एक नए उपयोगकर्ता के रूप में मुझे छवियों को अपलोड करने की अनुमति नहीं है, इसलिए यहां link माइक के पेड़ पर है जहां आप निम्नलिखित नोड्स को ओवरलैप करने वाले पिछले नोड्स के लेबल देख सकते हैं।

मैं विभिन्न चीजों की कोशिश की के साथ पाठ के पिक्सेल लंबाई पता लगाने के द्वारा इस समस्या को ठीक करने के लिए:

d3.select('.nodeText').node().getComputedTextLength(); 

हालांकि यह केवल काम करता है के बाद मैं पृष्ठ प्रदान की गई है जब मैं मैं पहले सबसे लंबे समय तक पाठ आइटम की लंबाई की जरूरत है प्रस्तुत करना।

nodes = tree.nodes(root).reverse(); 

var longest = nodes.reduce(function (a, b) { 
    return a.label.length > b.label.length ? a : b; 
}); 

node = vis.selectAll('g.node').data(nodes, function(d, i){ 
    return d.id || (d.id = ++i); 
}); 

nodes.forEach(function(d) { 
    d.y = (longest.label.length + 200); 
}); 

केवल स्ट्रिंग की लंबाई देता है, जबकि

d.y = (d.depth * 200); 

का उपयोग कर हर एक स्थिर लंबाई लिंक और के रूप में सुंदर जब आकार परिवर्तन नहीं करता है बनाता है:

इससे पहले कि मैं के साथ प्रस्तुत करना सबसे लंबे समय तक पाठ आइटम हो रही है नए नोड्स खोले या बंद हो जाते हैं।

क्या इस ओवरलैपिंग से बचने का कोई तरीका है? यदि हां, तो ऐसा करने और पेड़ की गतिशील संरचना को रखने का सबसे अच्छा तरीका क्या होगा?

3 संभव समाधान है कि मैं के साथ आने लेकिन यह है कि सरल नहीं हैं कर सकते हैं:

  1. लेबल लंबाई का पता लगा रहा है और एक अंडाकार जहां यह बच्चे नोड्स लगने का उपयोग कर। (जो लेबल को कम पठनीय बना देगा)
  2. लेबल की लंबाई का पता लगाने और तदनुसार समायोजित करने के लिए लिंक बताकर लेआउट को गतिशील रूप से स्केलिंग। (जो सबसे अच्छा होगा लेकिन वास्तव में मुश्किल लगता है
  3. svg तत्व स्केल करें और लेबल्स को चलाने के लिए स्क्रॉल बार का उपयोग करें। (सुनिश्चित नहीं है कि यह संभव है क्योंकि मैं इस धारणा पर काम कर रहा हूं कि एसवीजी को एक होना चाहिए ऊंचाई और चौड़ाई निर्धारित करें)

उत्तर

7

तो निम्न दृष्टिकोण लेआउट के विभिन्न स्तरों को विभिन्न "ऊंचाइयों" दे सकता है। आपको सावधानी बरतनी है कि एक रेडियल लेआउट के साथ आपको छोटे सर्किलों के लिए पर्याप्त फैलाने का जोखिम नहीं है बिना ओवरलैप के टेक्स्ट, लेकिन अब इसे अनदेखा करें।

कुंजी यह जानना है कि वृक्ष लेआउट बस चौड़ाई और ऊंचाई की मनमानी जगह पर चीजों को मानचित्र करता है और यह कि विकर्ण अल प्रक्षेपण नक्शे चौड़ाई (x) कोण और ऊंचाई (y) त्रिज्या के लिए। इसके अलावा त्रिज्या पेड़ की गहराई का एक साधारण कार्य है।

तो here पाठ लंबाई के आधार पर गहराई पुन: असाइन करने का एक तरीका है:

सबसे पहले, मैं का उपयोग करें (jQuery) के लिए अधिकतम पाठ आकार की गणना करने के:

var computeMaxTextSize = function(data, fontSize, fontName){ 
    var maxH = 0, maxW = 0; 

    var div = document.createElement('div'); 
    document.body.appendChild(div); 
    $(div).css({ 
     position: 'absolute', 
     left: -1000, 
     top: -1000, 
     display: 'none', 
     margin:0, 
     padding:0 
    }); 

    $(div).css("font", fontSize + 'px '+fontName); 

    data.forEach(function(d) { 
     $(div).html(d); 
     maxH = Math.max(maxH, $(div).outerHeight()); 
     maxW = Math.max(maxW, $(div).outerWidth()); 
    }); 

    $(div).remove(); 
    return {maxH: maxH, maxW: maxW}; 
} 

अब मैं रिकर्सिवली के स्तर के अनुसार तार की एक सरणी के साथ एक सरणी का निर्माण होगा:

var allStrings = [[]]; 
var childStrings = function(level, n) { 
    var a = allStrings[level]; 
    a.push(n.name); 

    if(n.children && n.children.length > 0) { 
     if(!allStrings[level+1]) { 
      allStrings[level+1] = []; 
     } 
     n.children.forEach(function(d) { 
      childStrings(level + 1, d); 
     }); 
    } 
}; 
childStrings(0, root); 

और फिर स्तर प्रति अधिकतम पाठ की लंबाई की गणना।

var maxLevelSizes = []; 
allStrings.forEach(function(d, i) { 
    maxLevelSizes.push(computeMaxTextSize(allStrings[i], '10', 'sans-serif')); 
}); 

तब मैं सभी स्तरों (छोटे वृत्त आइकन और कुछ गद्दी यह अच्छे लग रहे बनाने के लिए रिक्ति जोड़ने) का कुल पाठ चौड़ाई की गणना। यह अंतिम लेआउट का त्रिज्या होगा। ध्यान दें कि मैं बाद में उसी पैडिंग राशि का उपयोग करूंगा।

var padding = 25; // Width of the blue circle plus some spacing 
var totalRadius = d3.sum(maxLevelSizes, function(d) { return d.maxW + padding}); 

var diameter = totalRadius * 2; // was 960; 

var tree = d3.layout.tree() 
    .size([360, totalRadius]) 
    .separation(function(a, b) { return (a.parent == b.parent ? 1 : 2)/a.depth; }); 

अब हम सामान्य रूप से लेआउट को कॉल कर सकते हैं। एक आखिरी टुकड़ा है: विभिन्न स्तरों के लिए त्रिज्या को समझने के लिए हमें पिछले स्तर की त्रिज्या के संचयी योग की आवश्यकता होगी। एक बार हमारे पास यह है कि हम गणना की गई नोड्स को केवल नई त्रिज्या असाइन करते हैं।

// Compute cummulative sums - these will be the ring radii 
var newDepths = maxLevelSizes.reduce(function(prev, curr, index) { 
    prev.push(prev[index] + curr.maxW + padding);     
    return prev; 
},[0]);              

var nodes = tree.nodes(root); 

// Assign new radius based on depth 
nodes.forEach(function(d) { 
    d.y = newDepths[d.depth]; 
}); 

एह वॉयला! यह शायद सबसे साफ समाधान नहीं है, और शायद हर चिंता का समाधान नहीं करता है, लेकिन यह आपको शुरू करना चाहिए। मज़े करो!

+0

वाह, खेद है कि जवाब देने में इतना समय लगा लेकिन मुझे अब तक यह नहीं देखा। अंत में मैंने कभी भी इस समस्या को ठीक करने का अंत नहीं किया लेकिन आपके उत्तर के लिए धन्यवाद। मैं देखूंगा कि क्या मैं पुराना कोड पा सकता हूं और समस्या को ठीक करने का प्रयास करता हूं। – alengel