2016-08-11 1 views
-1

Ich arbeite mit this example eines Sunburst-Diagramms. Ich versuche, die äußere Ebene zu entfernen, die SKU-Informationen einer Kategorie anzeigt und nur Gruppen- und Kategorie-Layer hat. Ich habe noch nie mit D3 gearbeitet, also denke ich, dass die Baumtiefe ein Problem ist, aber ich konnte nicht herausfinden, welcher Teil des Codes bearbeitet werden soll, also habe ich einen alternativen Ansatz versucht.D3 Sunburst Diagrammtiefe

Was ich hoffte, würde das Problem lösen, alle JSON-Daten zu entfernen, die in der äußeren Schicht verwendet werden. Diese fiddle zeigen das Ergebnis. Leider scheint der Code nicht "schlau" genug zu sein, um die Lücken zu füllen/die Scheibenbreite anzupassen. Und da ich auch nicht schlauer bin, komme ich zu dir um Hilfe.

Aufgrund der Zeichenbeschränkung poste ich nur Teile des Codes, die ich für relevant halte.

Original-Datenstruktur:

var data1 = JSON.parse('[ 
{ 
"group":["Books","Arts","ZD111111"],"current":{"count":37} 
},{ 
"group":["Electronics","Audio","ZD111288"],"current":{"count":36} 
},{ 
"group":["Electronics","Camcorders","ZD111301"],"current":{"count":35} 
}, ... ]); 

Edited Datenstruktur:

var data1 = JSON.parse('[ 
{ 
"group":["Books","Arts"],"current":{"count":37} 
},{ 
"group":["Electronics","Audio"],"current":{"count":36} 
},{ 
"group":["Electronics","Camcorders"],"current":{"count":35} 
}, ... ]); 

Sunburst Diagramm:

treePath = ["group","category"], 

var controller = function(data, progress) { 
    if(progress === 100) { 
     data2 = $.extend(true, [], data2); 
     var flatData = []; 
     data.map(function(d) { 
      var item = {}; 
      for(var i = 0; i < treePath.length; i++) { 
       item[treePath[i]] = d.group[i]; 
      } 
      //item.size = d3.selectAll("input").filter(function (d) { return this.checked; }).attr("value") === "count" ? d.current.count : d.current.metrics.price.sum; 
      item.size = d.current.count; // always show count data    
      item.model = d; 
      return flatData.push(item); 
     }); 
     flatData.forEach(function(d) { 
      d.model.group = d.model.group[d.model.group.length - 1]; 
     }); 

     var treeData = genJSON(flatData, treePath.slice(0, treePath.length - 1)); 
     d3.select("#vis") 
      .datum(treeData) 
      .call(chart); 
    } 
}; 

function genJSON(csvData, groups) { 

    var genGroups = function(data) { 
     return _.map(data, function(element, index) { 
      return { name : index, children : element }; 
     }); 
    }; 

    var nest = function(node, curIndex) { 
     if (curIndex === 0) { 
      node.children = genGroups(_.groupBy(csvData, groups[0])); 
      _.each(node.children, function (child) { 
       nest(child, curIndex + 1); 
      }); 
     } 
     else { 
      if (curIndex < groups.length) { 
       node.children = genGroups(
        _.groupBy(node.children, groups[curIndex]) 
       ); 
       _.each(node.children, function (child) { 
        nest(child, curIndex + 1); 
       }); 
      } 
     } 
     return node; 
    }; 
    return nest({}, 0); 
} 

function isInt(n) { 
    return n % 1 === 0; 
} 

function sunburst() { 
    var instance = this, 
     svg = null, 
     timestamp = new Date().getTime(), 
     widgetHeight = 600, 
     widgetWidth = 600, 
     widgetSize = 'large', 
     margin = {top: 0, right: 0, bottom: 0, left: 10}, 
     width = widgetWidth - margin.left - margin.right, 
     height = widgetHeight - margin.top - margin.bottom, 
     radius = Math.min(width, height)/2, 
     x = d3.scale.linear().range([0, 2 * Math.PI]), 
     y = d3.scale.pow().exponent(1), 
     pgColor = d3.scale.ordinal().range([ 
      {"family": "Blue", 1: "#0000CC", 2: "#0099FF", 3: "#CCFFFF"}, 
      {"family": "Orange", 1: "#FF6600", 2: "#FFCC00", 3: "#FFFFCC"}, 
      {"family": "Green", 1: "#009900", 2: "#99CC33", 3: "#CCFF99"}, 
      {"family": "Red", 1: "#FF3333", 2: "#FF9999", 3: "#FFCCCC"}, 
      {"family": "Purple", 1: "#CC0099", 2: "#FF66CC", 3: "#FFCCFF"}, 
      {"family": "Grey", 1: "#7b7b7b", 2: "#999999", 3: "#eeeeee"}]), 
     luminance = d3.scale.sqrt() 
      .domain([0, 1e6]) 
      .clamp(true) 
      .range([90, 20]), 
     i = 0, 
     partition = d3.layout.partition().sort(function(a, b) { return d3.ascending(a.name || a[treePath[treePath.length - 1]], b.name || b[treePath[treePath.length - 1]])}), 
     arc = d3.svg.arc() 
      .startAngle(function(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x))); }) 
      .endAngle(function(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x + d.dx))); }) 
      .innerRadius(function(d) { return Math.max(0, d.y ? y(d.y) : d.y); }) 
      .outerRadius(function(d) { return Math.max(0, y(d.y + d.dy)); }); 

    function chart(selection) { 
     selection.each(function(data) { 
      instance.data = data; 
      width = widgetWidth - margin.left - margin.right; 
      height = widgetHeight - margin.top - margin.bottom; 
      radius = Math.min(width, height)/2; 

      y.range([0, radius]); 

      // Select the svg element, if it exists. 
      svg = d3.select(this).selectAll("svg").data([data]); 

      var gEnter = svg.enter() 
       .append("svg") 
       .attr("width", "600") 
       .attr("height", "600") 
       .append("g") 
       .attr("class", "main-group"); 

      gEnter.append("defs") 
       .append("clipPath") 
       .attr("id", "clip-" + timestamp) 
       .append("rect") 
       .attr("x", 0) 
       .attr("y", 0); 

      var sunburstGroup = gEnter.append("g") 
       .attr("class", "sunburst-area") 
       .append("g") 
       .attr("class", "sunburst-group"); 


      sunburstGroup.append("rect") 
       .attr("class", "sunburst-background") 
       .attr("x", 0) 
       .attr("y", 0) 
       .style("fill", "white"); 

      // Update the inner group dimensions. 
      var g = svg.select("g.main-group") 
       .attr("transform", "translate(" + (width/2 + margin.left) + "," + (height/2 + margin.top) + ")"); 

      g.select(".sunburst-background") 
       .attr("width", width) 
       .attr("height", height); 

      partition.value(function(d) { return d.size; }) 
      .nodes(data) 
      .forEach(function(d) { 
       d.key = key(d); 
      }); 

      var path = g.select(".sunburst-group").selectAll(".sunArcs") 
       .data(partition.nodes(data), function(d) { return d.key; }); 

      path.enter().append("path") 
       .attr("class", "sunArcs") 
       .attr("d", arc) 
       .style("fill", function(d) { 
        if(d.depth === 0) return "#fff"; 
        var color = pgColor(d.key.split(".")[0]); 
        return color[d.depth]; 
       }) 
       .style("fill-opacity", 0) 
       .on("click", click) 
       .on("mouseover", mouseover) 
       .on("mouseleave", mouseleave) 
       .each(function(d) { 
        this.x0 = d.x; 
        this.dx0 = d.dx; 
       }); 

      path.transition() 
       .duration(duration) 
       .style("fill-opacity", 1) 
       .attrTween("d", arcTweenUpdate); 

      path.exit() 
       .transition() 
       .duration(duration) 
       .attrTween("d", arcTweenUpdate) 
       .style("fill-opacity", 0) 
       .remove(); 

      function key(d) { 
       var k = [], p = d; 
       while (p.depth) k.push(p.name || p[treePath[treePath.length - 1]]), p = p.parent; 
       return k.reverse().join("."); 
      }  

      function click(d) { 
       path.transition() 
        .duration(duration) 
        .attrTween("d", arcTween(d)); 
      } 

      function getParents(d) { 
       var parents = [], p = d; 
       while (p.depth >= 1) { 
        parents.push(p); 
        p = p.parent; 
       } 
       return parents; 
      } 

      function mouseover(d) { 
       if(d.depth === 0) return; 
       var parentNodes = getParents(d); 
       // Fade all the arcs. 
       d3.selectAll(".sunArcs") 
       .style("opacity", 0.3); 

       // Highlight all arcs in path  
       d3.selectAll(".sunArcs").filter(function(d){ 
        return (parentNodes.indexOf(d) >= 0); 
       }) 
       .style("opacity", 1); 


       // Initialize variables for tooltip 
       var group = d.name || d[treePath[treePath.length - 1]], 
        valueFormat = d3.format(",.0f"), 
        textMargin = 5, 
        popupMargin = 10, 
        opacity = 1, 
        fill = d3.select(this).style("fill"), 
        hoveredPoint = d3.select(this), 
        pathEl = hoveredPoint.node(), 

       // Fade the popup stroke mixing the shape fill with 60% white 
        popupStrokeColor = d3.rgb(
         d3.rgb(fill).r + 0.6 * (255 - d3.rgb(fill).r), 
         d3.rgb(fill).g + 0.6 * (255 - d3.rgb(fill).g), 
         d3.rgb(fill).b + 0.6 * (255 - d3.rgb(fill).b) 
        ), 

       // Fade the popup fill mixing the shape fill with 80% white 
        popupFillColor = d3.rgb(
         d3.rgb(fill).r + 0.8 * (255 - d3.rgb(fill).r), 
         d3.rgb(fill).g + 0.8 * (255 - d3.rgb(fill).g), 
         d3.rgb(fill).b + 0.8 * (255 - d3.rgb(fill).b) 
        ), 

       // The running y value for the text elements 
        y = 0, 
       // The maximum bounds of the text elements 
        w = 0, 
        h = 0, 
        t, 
        box, 
        rows = [], p = d, 
        overlap; 

       var hoverGroup = d3.select(this.parentNode.parentNode.parentNode.parentNode).append("g").attr("class", "hoverGroup"); 

       // Add a group for text 
       t = hoverGroup.append("g"); 
       // Create a box for the popup in the text group 
       box = t.append("rect") 
        .attr("class", "tooltip"); 


        if(!isInt(d.value)) { 
         valueFormat = d3.format(",.2f"); 
        } 


       while (p.depth >= 1) { 
        rows.push(treePath[p.depth - 1] + ": " + (p.name || p[treePath[treePath.length - 1]])); 
        p = p.parent; 
       } 
       rows.reverse(); 
       rows.push("Volume: " + valueFormat(d.value)); 

       t.selectAll(".textHoverShapes").data(rows).enter() 
        .append("text") 
        .attr("class", "textHoverShapes") 
        .text(function (d) { return d; }) 
        .style("font-size", 14); 

       // Get the max height and width of the text items 
       t.each(function() { 
        w = (this.getBBox().width > w ? this.getBBox().width : w); 
        h = (this.getBBox().width > h ? this.getBBox().height : h); 
       }); 

       // Position the text relatve to the bubble, the absolute positioning 
       // will be done by translating the group 
       t.selectAll("text") 
        .attr("x", 0) 
        .attr("y", function() { 
         // Increment the y position 
         y += this.getBBox().height; 
         // Position the text at the centre point 
         return y - (this.getBBox().height/2); 
        }); 

       // Draw the box with a margin around the text 
       box.attr("x", -textMargin) 
        .attr("y", -textMargin) 
        .attr("height", Math.floor(y + textMargin) - 0.5) 
        .attr("width", w + 2 * textMargin) 
        .attr("rx", 5) 
        .attr("ry", 5) 
        .style("fill", popupFillColor) 
        .style("stroke", popupStrokeColor) 
        .style("stroke-width", 2) 
        .style("opacity", 0.95); 

       // Move the tooltip box next to the line point 
       t.attr("transform", "translate(" + margin.left + " , " + 10 + ")"); 
      } 

      // Mouseleave Handler 
      function mouseleave(d) { 
       d3.selectAll(".sunArcs") 
       .style("opacity", 1); 
       d3.selectAll(".hoverGroup") 
       .remove(); 
      }    

      // Interpolate the scales! 
      function arcTween(d) { 
       xd = d3.interpolate(x.domain(), [d.x, d.x + d.dx]), 
       yd = d3.interpolate(y.domain(), [d.y, 1]), 
       yr = d3.interpolate(y.range(), [d.y ? 20 : 0, radius]); 
       return function(d, i) { 
        return i 
        ? function(t) { return arc(d); } 
        : function(t) { x.domain(xd(t)); y.domain(yd(t)).range(yr(t)); return arc(d); }; 
       }; 
      } 

      function arcTweenUpdate(a) { 
       var updateArc = this; 
       var i = d3.interpolate({x: updateArc.x0, dx: updateArc.dx0}, a); 
       return function(t) { 
        var b = i(t); 
        updateArc.x0 = b.x; 
        updateArc.dx0 = b.dx; 
        return arc(i(t)); 
       }; 
      }    
     }); 
    } 

Ich werde entweder Lösung akzeptieren.

Danke.

+0

Es gibt eine gute Chance, niemand wird diese Frage beantworten ... es ist nicht sehr spezifisch, was Sie fordern .. Aber wer weiß :-) – Ryan

Antwort

0

Nach dem Entfernen der SKU-Gruppe sind mehrere Objekte mit denselben Gruppen vorhanden. Beispiel:

{ 
    "group": ["Jewelry", "Diamonds"], 
    "current": { 
     "count": 26 
    } 
} 

{ 
    "group": ["Jewelry", "Diamonds"], 
    "current": { 
     "count": 28 
    } 
} 

sollten Sie entweder die Daten korrigieren oder diese Einträge summieren. Ich habe Ihre Geige aktualisiert, nachdem die Aggregation Einträge mit gleichen Gruppen zu testen, und es sieht jetzt gut (https://jsfiddle.net/zwg31n7h/):

var oldData = _.find(flatData, function(f){ 
       var found = true; 
       _.each(treePath, function(t){ 
        if(f[t] !== item[t]) { 
         found = false; 
        } 
       }); 
       return found; 
      }); 
      if(oldData) { 
       oldData.size += item.size; 
       oldData.model.current.count += item.size; 
      } else { 
       flatData.push(item); 
      } 
+0

Ich bin froh, dass das Skript "schlauer" ist als ich. Ich habe die Tatsache völlig übersehen, dass der Verlust der SKU-Gruppe Duplikate erzeugt. : D Danke. – skrunic