在行+条形图中使用d3画笔时出现问题(放大行+条形图)

时间:2015-04-09 12:46:51

标签: javascript jquery d3.js charts data-visualization

我正在尝试使用画笔来缩放我在d3.js中的自定义图表,但它的表现不应该如此。任何想法可能是错的 这里是js fiddle http://fiddle.jshell.net/saurabh_nitc10/od8gfsd3/9/

就像在这个小提琴http://fiddle.jshell.net/CjaD3/1/中刷完酒吧后走出y轴一样。任何想法

现有的小提琴出了什么问题。它不像在缩放后应该做的那样。请帮助。我刚刚更新了小提琴

这是我创建的插件。

(function($) {
$.dualAxis = {};
var xMapObject=[];
var svg = '';
var focus = '';
var tip = '';
function DualAxis(element, options) {
    this.$element = $(element);
    this.options = options;
    this.margin = {top: 20, right: 80, bottom: 30, left: 40},
    width = $(this.$element.selector).width() - this.margin.left - this.margin.right,
    height = $(this.$element.selector).height() - this.margin.top - this.margin.bottom;
    this.options.height = (this.options.height == null? height: this.options.height);
    this.options.width = (this.options.width == null? width: this.options.width);
    this.rangeMax = this.getMaxX().length*100;
    if (this.rangeMax > 14000) this.rangeMax = 14000;
    this.enabled = true;
}

DualAxis.prototype = {
    draw: function(){
        this.options.data.bar.forEach(function(d) {
            d.value = +d.value;
        });
        this.options.data.line.forEach(function(d) {
            d.value = +d.value;
        });
        tip = d3.tip()
          .attr('class', 'd3-tip')
          .html(function(d) { 
            var name= xMapObject[d.date];if(name == undefined){name=d.date;}
            var table = '<table class="table table-condensed">'
                        + '<thead>'
                        + '<tr><th colspan="2" style="text-align:center"class="city">'+name+'</th></tr>'
                        + '</thead>'
                        + '<tbody>'
                        + '<tr><td>Total Sales</td><td class="visits">'+d.value+'</td></tr>'
                        + '</tbody>'
                        + '</table>';
            return table; 
          })
          .style({border: '1px solid #fff', 'box-shadow': '1px 1px 4px rgba(0,0,0,0.5)', 'border-radius': 'none','background':'#fff','color':'#555'})
          .offset([-12, 0]);
        // if(this.options.data.events.length > 1){
            // xOffset = (this.options.width/this.options.data.events.length) + 40;
        // } else {
            // xOffset = this.options.width/2;
        // }
        xOffset = 62;
        svg = this.getSvg();
        svg == null ? svg = d3.select(this.$element.selector).append("svg"): svg;
        svg = svg
        .attr("height", this.options.height+this.margin.bottom+this.margin.top)
        .attr("width",this.options.width+this.margin.right+this.margin.left)
        .attr('class',this.options.svgClassName);
        svg.append("defs").append("clipPath")
            .attr("id", "clip")
            .append("rect")
            .attr("width", this.options.width)
            .attr("height", this.options.height);
        focus = svg.append("g").attr("class", "focus").attr("transform", "translate(" + xOffset + "," + 40 + ")");
        svg.call(tip);
        //this.drawBackground(focus);

        this.drawRect(focus,tip);
        this.drawXAxis(focus);
        this.drawY1Axis(focus);
        this.drawY2Axis(focus);
        this.drawLine(focus);
        this.drawLineLow(focus);
        this.drawLineMedium(focus);
        this.drawLineHigh(focus);
        if (this.options.showLegend)this.drawLegend(focus);
        this.zoomBehaviour(focus);
    },
    drawRect: function(svg,tip){
        x = this.getX();
        x2 = this.getX();
        y1 = this.getY1();
        y2 = this.getY2();
        height = this.options.height - (this.options.height / 3);
        transTime = 0;
        if(this.options.animate) transTime = 1000;

        svg.selectAll("rect.bar").data(this.options.data.bar).enter().append("rect").attr("class","bar").attr("width", this.options.width/this.options.data.bar.length).attr("x", function (d) {
            return x(d.date);
        }).attr("y", height).attr("height", 0).style("fill", function (d,i) {
            return "#89A54E";
        }).on('mouseover', tip.show)
        .on('mouseout', tip.hide).transition().duration(transTime).attr("y", function (d) {
            if(isNaN(y1(d.value))) return 0;return y1(d.value);
        }).attr("height", function (d) {
             if(isNaN(y1(d.value))) return 0; return (height - y1(d.value));
        }).style("fill", function(d) { return "#89A54E";}).attr("rx","1.5").attr("ry","1.5");
    },

    drawXAxis:function(svg){
        svg.append("g").attr("class", "x axis").attr("transform", "translate(0," + height + ")").call(this.getXAxis()).append("text").attr("transform", "translate(" + xOffset + "," + 40 + ")").style("text-anchor", "end").text(this.options.xAxisText).style("font-weight", "bold");
    },
    drawY1Axis:function(svg){

        svg.append("g").attr("class", "y axis").call(this.getY1Axis()).append("text").attr('id','y1AxisText').attr("transform", "rotate(-90)").attr("y",-36 ).attr("x", -(this.options.height/5)).style("text-anchor", "end").style("fill", "#266866").style("font-weight", "bold").style("letter-spacing", "1px").text(this.options.y1AxisText);
    },
    drawY2Axis:function(svg){
        svg.append("g").attr("class", "y axis").call(this.getY2Axis()).attr("transform", "translate(" + this.options.width + " ,0)")    .append("text").attr('id','y2AxisText').attr("transform", "rotate(-90)").attr("y",47 ).attr("x", -(this.options.height/5)).style("text-anchor", "end").style("fill", "#266866").style("font-weight", "bold").style("letter-spacing", "1px").text(this.options.y2AxisText);
    },
    drawLegend: function(svg){
        legend = svg.append("g").attr("class", "legend").attr('transform', 'translate(-30,'+(height+50)+')');
        max = d3.max(this.options.values,function(d){return d.length;});
        legend.selectAll('rect').data(this.options.values).enter().append("rect").attr("x", function(d,i){return (i*149);}).attr("y", "0").attr("width", 12).attr("height", 12).style("fill", function(d,i){return color(i);});
        legend.selectAll('text').data(this.options.values).enter().append("text").attr("x", function (d, i) {return (i*149+15);}).attr("y", "10").text(function (d) {return d;});
    },
    getSvg: function(){
        return this.options.svg;
    },
    getXAxis:function(){
        //var x = d3.scale.ordinal().rangeRoundBands([0, this.options.width], 0);
        return  d3.svg.axis().scale(x).tickFormat(d3.time.format("%b'%y")).orient("bottom");
        //return d3.svg.axis().scale(x).tickValues(x.domain().filter(function(d, i) {return !(i % 10); })).orient("bottom");
    },
    getY1Axis:function(){
        return d3.svg.axis().scale(y1).orient("left").tickFormat(d3.format(".2s"));
    },
    getY2Axis:function(){
        return d3.svg.axis().scale(y2).orient("right").tickFormat(d3.format(".2s"));
    },
    getMaxX: function(){ //for ordinal we dont know what to scale 

        return  this.options.data.dateForxAxis.map(function (d) {
            return d.date;});
    },
    getMaxY1: function(){
        return d3.max(this.options.data.bar, function (d) {return d.value;});
    },
    getMaxY2: function(){
        return d3.max(this.options.data.line, function (d) {return d.value;});
    },
    getX: function(){
        return d3.time.scale().range([0, this.options.width]).domain(d3.extent(this.options.data.dateForxAxis, function(d) { return d.date; }));
    },
    getY1: function(){
        return d3.scale.linear().range([this.options.height - (this.options.height / 3), 0]).domain([0, this.getMaxY1()]);
    },
    getY2: function(){
        return d3.scale.linear().range([this.options.height - (this.options.height / 3), 0]).domain([0, this.getMaxY2()]);
    },
    drawBackground: function(vis){
        vis.append("rect").attr("x", 0).attr("y", 0).attr("width", this.options.width ).attr("height", this.options.height - 50).style("fill", "grey").attr("transform", "translate(0,0)").style("opacity", "0").attr("class","background").attr("id", "background");
    },
    zoomBehaviour: function(vis){
        var that = this;
        //zoomBehaviour = d3.behavior.zoom().scaleExtent([1, 1]).on("zoom", zoom);
        brush = d3.svg.brush().x(x2).on("brush", brushed);
        width = this.options.width;
        vis.append("g").attr("class","x brush").call(brush).selectAll("rect").attr("y",-6).attr("height",this.options.height+7);
        function brushed(){
            x.domain(brush.empty() ? x2.domain() : brush.extent());
            vis.selectAll("rect.bar")
            .attr("transform", function(d) { return "translate(" + x(d.date) + ",0)"; })
             vis.select(".x.axis").call(that.getXAxis());
             //vis.select(".line").attr("d", that.getLine());
        }
    },
    drawLine:function(svg){
        svg.append('path').datum(this.options.data.line).attr("class", "line").attr("d", this.getLine());
    },
    getLine:function(){
        return d3.svg.line().interpolate("basis") .x(function(d) {return x(d.date); }).y(function(d) { return y2(d.value); });
    },
    drawLineLow:function(svg){
        svg.append('path').datum(this.options.data.future).attr("class", "lineLow").attr("d", this.getLineLow()).style("stroke-dasharray", ("3, 3"));
    },
    getLineLow:function(){
        return d3.svg.line().interpolate("basis") .x(function(d) {return x(d.date); }).y(function(d) { return y2(d.low); });
    },
    drawLineMedium:function(svg){
        svg.append('path').datum(this.options.data.future).attr("class", "lineMedium").attr("d", this.getLineMedium());
    },
    getLineMedium:function(){
        return d3.svg.line().interpolate("basis") .x(function(d) {return x(d.date); }).y(function(d) { return y2(d.medium); });
    },
    drawLineHigh:function(svg){
        svg.append('path').datum(this.options.data.future).attr("class", "lineHigh").attr("d", this.getLineHigh()).style("stroke-dasharray", ("3, 3"));
    },
    getLineHigh:function(){
        return d3.svg.line().interpolate("basis") .x(function(d) {return x(d.date); }).y(function(d) { return y2(d.high); });
    },

};
$.fn.dualAxis = function(options){

    options = $.extend({}, $.fn.dualAxis.defaults, options);
    if(options.data === '' || options.data === null){
        var err = 'dualAxis Error: Data Attribute Cannot be Empty or Null.';
        (typeof(console) != 'undefined' && console.error) ? 
            console.error(err) : 
            alert(err);
    }
    function elementOptions(ele, options) {
        return $.metadata ? $.extend({}, options, $(ele).metadata()) : options;
    };
    function get(ele) {
        var gb = $.data(ele, 'gb');
        if (!gb) {
            gb = new DualAxis(ele,elementOptions(ele, options));
            $.data(ele, 'gb', gb);
        }
        return gb;
    }
    var gb = get(this);
    gb.draw();
};

$.fn.dualAxis.defaults = {
        svgClassName: "dualAxis",
        svg: null,
        xAxisText: 'x-axis',
        y1AxisText: 'y1-axis',
        y2AxisText: 'y2-axis',
        maxX: null,
        maxyY: null,
        height:null,
        width:null,
        animate: true,
        color: ["#3366cc", "#dc3912", "#ff9900", "#109618"],
        showLegend:true,
        data: '',
    };
})(jQuery);

这是数据的格式

{
"bar": [
    {
        "date": "50_2012",
        "value": "88787"
    },
    {
        "date": "155_2012",
        "value": "50573"
    },
     {
        "date": "155_2013",
        "value": "5057"
    }
],
"dateForxAxis": [
    {
        "date": "45_2012"
    },
    {
        "date": "155_2012"
    },
    {
        "date": "260_2013"
    }
],
"future": [
    {
        "high": "87878",
        "medium": "55535",
        "low": "1212"
    },
    {
        "high": "187878",
        "medium": "255535",
        "low": "14212"
    }
],
"line": [
    {
        "date": "50_2012",
        "value": "8787"
    },
    {
        "date": "60_2012",
        "value": "47474"
    },
     {
        "date": "168_2012",
        "value": "49474"
    }
]
};

调用插件

$('#dualAxis').dualAxis({
            data: viewData1,
            xAxisText: 'Time',
            y1AxisText:'Transactions',
            y2AxisText:'Sales',
            animate:true,
            showLegend:false
        });

请建议我做错了什么。当它缩放时,它应该缩放甚至线条和其他三条线。

2 个答案:

答案 0 :(得分:1)

在拉丝方法中,您正在平移条形而不是设置新的x位置(使它们根据图形外部的原始x位置进行平移)。在拉丝方法中重新设置x位置将在缩放时正确放置条:

vis.selectAll("rect.bar").attr("x", function (d) {
  return x(d.date);
});

你的jsfiddle的一个分支,在http://fiddle.jshell.net/brendaz/zr6kkgaa/

处有这个变化

答案 1 :(得分:0)

除了你没有在brushed()函数中更新rect.bar元素的宽度外,每件事看起来都很好。你只是更新x坐标。在您的情况下,rect.bar元素宽度始终是常量。而且我还注意到,当你拖动画笔时,由于左侧和右侧的额外填充(可能是故意的),元素会离开受限区域。

所以只需解决问题,你就可以了。