即使存在关键功能,D3也不会保持对象的恒定性

时间:2015-01-29 07:47:16

标签: javascript d3.js

我正在尝试使用d3(在此特定场景中使用饼图)编写可重用的图形组件。我是d3的新手,也是编写高度可重用组件的相对缺乏经验的人。这是我到目前为止,我已经使用类似的代码显示了一个饼图,通过将一个键函数传递给data但是当我试图制作相同的时候,对象的常量会以某种方式失败(切片出现故障)对于可重复使用的组件。

我知道此代码中有很多关注点可以为用户提供更多选项以及更清晰的代码。

 function pieChart(){
        var _pie ={};
        var _width = 960,
                _height = 600,
                _margins = {top:30,left:30,right:30,bottom:30},
                _x,_y,_data = [],
                _color = d3.scale.category10(),
                _svg,
                _innerRadius=0,
                _radius = Math.min(_width,_height)/2 - (_margins.top/2 + _margins.bottom/2),  
                _layout = d3.layout.pie(),
                _key = function(d) { return d.data.key;},
                _value= function(d) { return d.data.val;},
                _bodyG,
                _arc;

        _pie.color = function(c){
            if(!arguments.legnth) return _color;
            _color = c;
            return  _pie;
        }

        _pie.value = function(v){
            if(!arguments.legnth) return _value;
            _value = v;
            return  _pie;
        }
        _pie.key = function(k){
            if(!arguments.legnth) return _key;
            _key= k;
            return  _pie;
        }
        _pie.width = function(w){
            if(!arguments.length) return _width;
            _width = w;
            return _pie;
        }
        _pie.height= function(h){
            if(!arguments.length) return _height;
            _height= h;
            return _pie;
        }
        _pie.margins = function(m){
            if(!arguments.length) return _margins;
            _margins = m;
            return _pie;
        }
        _pie.color= function(c){
            if(!arguments.length) return _color;
            _color = c;
            return _pie;
        }
        _pie.innerRadius= function(i){
            if(!arguments.length) return _innerRadius;
            _innerRadius = i;
            return _pie;
        }

        _pie.outerRadius= function(i,recalculate){
            recalculate = typeof recalculate !== 'undefined'? recalculate: false;
            if(!arguments.length){
                if(recalculate || !_radius)
                    _radius = Math.min(_width,_height)/2 - (_margins.top + _margins.bottom)/2;
                return _radius;
            }
            _radius= i;
            return _pie;
        }

        _pie.render= function(options){
            if(!_svg){
                _svg = d3.select("#pie-chart").append("svg")
                    .attr("height",_height)
                    .attr("width",_width)
                    .append("g")
                    .attr("transform","translate("+_width/2 + "," + _height/2 + ")");
            }
            if(options && options.layout) _layout= options.layout;

            if(options && options.sort) _layout.sort(options.sort);

            if(options && options.value) _layout.value(options.value);
            else _layout.value(function(d){return d.val});

            renderPie(_svg);
            renderLines(_svg);
            renderLabels(_svg);
        }

        _pie.layout = function(l){
            if(!arguments.length) return _layout;
            _layout = l;
            return _pie;
        }
        _pie.data=function(d){
            if(!arguments.length) return _data;
            _data = d;
            return _pie;
        }
        _pie.arc = function(a){
            if(!arguments.length){
                if(!_arc)
                _arc= d3.svg.arc()
                    .outerRadius(_radius)
                    .innerRadius(_innerRadius);
                return _arc;
            }
            _arc = a;
            return _pie;
        }
        _pie.key = function(k){
            if(!arguments.length || typeof k != 'function') return _key;
            _key = k;
            return _pie;
        }
        _pie.value= function(v){
            if(!arguments.length || typeof v != 'function') return _value;
            _value = v;
            return _pie;
        }
        _pie._textPos= function(d){
            var xc = _arc.centroid(d)[0];
            var yc = _arc.centroid(d)[1];
            var r = _radius -10;
            var effectiveX = xc>0 ? _radius+50 : -_radius-50;
            var effectiveY = yc>0 ? (r*yc)/Math.sqrt(xc*xc + yc*yc)+50 : (r*yc)/Math.sqrt(xc*xc + yc*yc)-20;
            return "translate(" + effectiveX+ ","+effectiveY+")";
        }

        _pie.textPos = function(d){
            if(!arguments.length) return _textPos;
            _textPos = d;
            return _pie;
        }

        _pie._arcIdentifier = function(d){
            return "each-arc-"+_key(d).toString().replace(/ /g,"_");
        }

        _pie._line1x1 = function(d){
            var xc = _arc.centroid(d)[0];
            var yc = _arc.centroid(d)[1];
            var r = _radius -10;
            return (r*xc)/Math.sqrt(xc*xc + yc*yc);
        }
        _pie._line1x2 = function(d){
            var xc = _arc.centroid(d)[0];
            var yc = _arc.centroid(d)[1];
            var r = _radius -10;
            var xret= (r*xc)/Math.sqrt(xc*xc + yc*yc);
            return xc>0 ? xret+50: xret-50;
        }
        _pie._line2x1 = function(d){
            var xc = _arc.centroid(d)[0];
            var yc = _arc.centroid(d)[1];
            var r = _radius -10;
            var xret= (r*xc)/Math.sqrt(xc*xc + yc*yc);
            return xc>0 ? xret+50: xret-50;
        }
        _pie._line2x2 = function(d){
            var xc = _arc.centroid(d)[0];
            return xc>0 ? _radius+40: -_radius-40;
        }
        _pie._line1y1 = function(d){
            var xc = _arc.centroid(d)[0];
            var yc = _arc.centroid(d)[1];
            var r = _radius -10;
            return (r*yc)/Math.sqrt(xc*xc + yc*yc);
        }

        _pie._line1y2 = function(d){
            var xc = _arc.centroid(d)[0];
            var yc = _arc.centroid(d)[1];
            var r = _radius -10;
            return yc>0 ? (r*yc)/Math.sqrt(xc*xc + yc*yc)+50 : (r*yc)/Math.sqrt(xc*xc + yc*yc)-20;
        }
        _pie._line2y1 = function(d){
            var xc = _arc.centroid(d)[0];
            var yc = _arc.centroid(d)[1];
            var r = _radius -10;
            return yc>0 ? (r*yc)/Math.sqrt(xc*xc + yc*yc)+50 : (r*yc)/Math.sqrt(xc*xc + yc*yc)-20;
        }
        _pie._line2y2 = function(d){
            var xc = _arc.centroid(d)[0];
            var yc = _arc.centroid(d)[1];
            var r = _radius -10;
            return yc>0 ? (r*yc)/Math.sqrt(xc*xc + yc*yc)+50 : (r*yc)/Math.sqrt(xc*xc + yc*yc)-20;
        }

        _pie.line1x1 = function(d){
            if(!arguments.length) return _line1x1;
            _line1x1 = d;
            return _pie;
        }

        _pie.line1x2 = function(d){
            if(!arguments.length) return _line1x2;
            _line1x2 = d;
            return _pie;
        }
        _pie.line1y1 = function(d){
            if(!arguments.length) return _line1y1;
            _line1x1 = d;
            return _pie;
        }
        _pie.line1y2 = function(d){
            if(!arguments.length) return _line1y2;
            _line1y2 = d;
            return _pie;
        }
        _pie.line2x1 = function(d){
            if(!arguments.length) return _line2x1;
            _line2x1 = d;
            return _pie;
        }
        _pie.line2x2 = function(d){
            if(!arguments.length) return _line2x2;
            _line2x2 = d;
            return _pie;
        }
        _pie.line2y1 = function(d){
            if(!arguments.length) return _line2y1;
            _line2y1 = d;
            return _pie;
        }
        _pie.line2y2 = function(d){
            if(!arguments.length) return _line2y2;
            _line2y2 = d;
            return _pie;
        }



        function renderLabels(svg){
            _bodyG.append("text")
                .attr("transform",function(d){return _pie._textPos(d)})
                .attr("dy", ".35em")
                .style("text-anchor", function(d){return _pie.arc().centroid(d)[0]>0? "start":"end";})
                .text(_pie.key());
        }


        function renderPie(svg){
            _pie.arc();
            _bodyG = svg.selectAll(".arc")
                .data(_pie.layout()(_pie.data()),_pie.key()) //Worked perfectly before but now fails
                .enter().append("g")
                .order()
                .attr("class","arc");
            _bodyG.append("path")
                .attr("d",_arc)
                .attr("class",_pie._arcIdentifier)
                .style("fill",function(d){return _pie.color()(_pie.value()(d));})
        }
        function renderLines(svg){
            _bodyG.append("line")
                .attr("stroke","black")
                .attr("x1",_pie._line1x1)
                .attr("x2",_pie._line1x2)
                .attr("y1",_pie._line1y1)
                .attr("y2",_pie._line1y2);
            _bodyG.append("line")
                .attr("stroke","black")
                .attr("x1",_pie._line2x1)
                .attr("x2",_pie._line2x2)
                .attr("y1",_pie._line2y1)
                .attr("y2",_pie._line2y2);
        }
        return _pie;
    }

我正在寻找这样的输出:

enter image description here

1 个答案:

答案 0 :(得分:2)

[聊天中的澄清:问题不在于对象的持久性,而是以与数据中不同的顺序绘制饼图的切片。]

问题在于您要求饼图布局对数据进行排序:

_layout.sort(options.sort)

这会重新排列数据,因此切片会以不同的顺序出现。要解决此问题,您可以关闭排序或在数据中提供一个键,您可以对其进行排序以获得所需的顺序。