c3.js散点图轴未缩放以调整点半径

时间:2015-09-04 15:13:19

标签: javascript c3.js

我创建了一个c3散点图,根据数据生成不同大小的点。如果图形的最左侧或最右侧附近的点相对较大,则它不会被包含在图形中,并且该点的一部分被切断。如果我添加静态填充,图表不会针对不同的情况进行适当缩放,并且有时会有太多或太少的填充。有没有办法通过动态生成填充来包含图中的点?

代码:

function getChart(gridData) {

    var colors = ['#b2182b', '#d6604d', '#f4a582', '#fddbc7', '#f7f7f7', '#d1e5f0', '#92c5de', '#4393c3', '#4392c3', '#2166ac'];
    var columns = [];
    var mySize = {};
    var mySizeArray = [];
    var myXs = {};
    var myNames = [];
    var myPointColors;
    myPointColors = {};
    var pointSize;
    var newData = extractPointsFromGrid(gridData);

    pointSize = function (sizeVal, sizes) {
        var Incidence = sizeVal;
        var MIN_incidence = d3.min(sizes);
        var MAX_incidence = d3.max(sizes);
        var qtl3 = d3.mean(sizes);

        //noinspection OverlyComplexArithmeticExpressionJS
        var s = ((Incidence - MIN_incidence) * (50 - 10)) / (MAX_incidence - MIN_incidence) + 3;

        return (s + Math.floor(qtl3) > 3) ? s + Math.floor(qtl3) : 3;
    };

    var bubbleSizes = function (sizes) {
        var _sizes = typeof sizes === 'object' ? sizes : [];
        var len = (typeof _sizes === 'object') ? sizes.length : 0;

        var sizesArray = _.pluck(_sizes, 'iCumulative');

        var reacsArray = _.pluck(_sizes, 'reac');
        var newSizes = [];
        _sizes.forEach(function (size) {

            var newSize = pointSize(Math.abs(size.iCumulative), sizesArray);
            newSizes.push({'reac': size.reac, 'size': newSize});
        });
        window.sizes = newSizes;
        return newSizes;
    };

    var myNameIndex = [];
    var myPointSizes = [];
    var i = 0;

    var myColors = bubbleColors.reverse();
    var myPts = bubbleSizes(newData);
    var dynamicPadding = addDynamicPadding(myPts, newData);

    newData.forEach(function (d) {
        var name = d.reac;
        var myRor = [d.reac];
        var myPs = [d.reac + "_Primary Suspect"];

        myRor.push(d.ROR);
        myPs.push(d.PS);
        myNames.push(d.reac);
        myNameIndex[i] = d.reac;
        myPointColors[d.reac] = myColors[i];

        columns.push(myRor);
        columns.push(myPs);
        myXs[myRor[0]] = myPs[0];
        mySize[d.reac] = d.iCumulative;
        myNameIndex[d.reac] = d.PS;
        myPointSizes.push = {'reac': d.reac, 'size': d.iCumulative};

        i++;
    });

    var chart = c3.generate({
        bindto: '#rxsignal-chart-bubble',
        size: {
            height: 200
        },
        data: {
            xs: myXs,
            columns: columns,
            type: 'scatter',
            colors: myPointColors
        },
        axis: {
            x: {
                label: 'Primary Suspect Cases',
                tick: {
                    fit: false
                },
                // padding: {top: 200, left: 0, right: 0, bottom: 0}
            },
            y: {
                label: 'ROR',
                tick: {
                    fit: false,
                    format: function (d) {
                        return (d < 0) ? '' : d;
                    }
                },
                // padding: {top: 5, left: 5, right: 100, bottom: 5}
            }
        },
        point: {
            r: function (d) {
                pointSize = _.where(myPts, {reac: d.id})[0];
                return pointSize.size;
            },
            focus: {
                expand: {
                    enabled: false,
                    r: function (d) {
                        return d.r;
                    }
                }

            }
        },
        tooltip: {

            format: {
                title: function (d) {

                    return false;

                },
                name: function (name) {
                    return name;
                },
                value: function (value, ratio, id, size, x) {

                    var numFormat = d3.format(',');
                    var decFormat = d3.format('.');
                    var pctgFormat = d3.format('.4p');

                    return '<tr colspan="2"><td>Primary Suspect Cases</td><td>' + numFormat(myNameIndex[id]) + '</td></tr>' + '<tr><td>ROR</td><td>' + numFormat(value) + '</td></tr>';

                }
            }
        }
    });

    var getPaddingChange = function (chart) {
        var change = {
            top: 0,
            left: 0,
            right: 0,
            bottom: 0
        };

        var m = chart.internal.main.node().parentNode.getBoundingClientRect();
        // the chart area is shifted by this transform - so we need to adjust the point coordinates by this amount
        var t = d3.transform(chart.internal.main.attr("transform")).translate;
        // loop through each point
        chart.internal.main.selectAll('.' + c3.chart.internal.fn.CLASS.circle).each(function () {
            var c = this.getBBox();

            // left clipping
            if (c.x < -t[0])
                change.left = Math.max(change.left, -(c.x + t[0]));
            // right clipping
            if ((c.x + c.width) > (m.width - t[0]))
                change.right = Math.max(change.right, (c.x + c.width) - (m.width - t[0]));
            // top clipping
            if (c.y < -t[1])
                change.top = Math.max(change.top, -(c.y + t[1]));
            // bottom clipping
            if ((c.y + c.height) > (m.height - t[1]))
                change.bottom = Math.max(change.bottom, (c.y + c.height) - (m.height - t[1]));
        })

        return change;
    }

    var change = getPaddingChange(chart);

    chart.internal.config.padding_top = chart.internal.getCurrentPaddingTop() + change.top;
    chart.internal.config.padding_bottom = chart.internal.getCurrentPaddingBottom() + change.bottom;
    chart.internal.config.padding_left = chart.internal.getCurrentPaddingLeft() + change.left;
    chart.internal.config.padding_right = chart.internal.getCurrentPaddingRight() + change.right;
    // force a redraw
    chart.flush();

    // remove clip path
    chart.internal.main.select('.' + c3.chart.internal.fn.CLASS.chart).attr('clip-path', null);

}

1 个答案:

答案 0 :(得分:3)

调整C3图表填充以适合图表元素

调整图表填充(而不是轴填充)会更简单。这也可以确保一旦删除clippath,你的圈子就不会被剪裁

这是主要功能,可根据圆圈的剪裁程度计算(如果有的话) - 即它可以为您提供添加到填充所需的额外调整

var getPaddingChange = function (chart) {
    var change = {
        top: 0,
        left: 0,
        right: 0,
        bottom: 0
    };

    var m = chart.internal.main.node().parentNode.getBoundingClientRect();
    // the chart area is shifted by this transform - so we need to adjust the point coordinates by this amount
    var t = d3.transform(chart.internal.main.attr("transform")).translate;
    // loop through each point
    chart.internal.main.selectAll('.' + c3.chart.internal.fn.CLASS.circle).each(function () {
        var c = this.getBBox();

        // left clipping
        if (c.x < -t[0])
            change.left = Math.max(change.left, -(c.x + t[0]));
        // right clipping
        if ((c.x + c.width) > (m.width - t[0]))
            change.right = Math.max(change.right, (c.x + c.width) - (m.width - t[0]));
        // top clipping
        if (c.y < -t[1])
            change.top = Math.max(change.top, -(c.y + t[1]));
        // bottom clipping
        if ((c.y + c.height) > (m.height - t[1]))
            change.bottom = Math.max(change.bottom, (c.y + c.height) - (m.height - t[1]));
    })

    return change;
}

这就是它如何适应流程的其余部分 - chart是你的C3图表对象

var change = getPaddingChange(chart);

chart.internal.config.padding_top = chart.internal.getCurrentPaddingTop() + change.top;
chart.internal.config.padding_bottom = chart.internal.getCurrentPaddingBottom() + change.bottom;
chart.internal.config.padding_left = chart.internal.getCurrentPaddingLeft() + change.left;
chart.internal.config.padding_right = chart.internal.getCurrentPaddingRight() + change.right;
// force a redraw
chart.flush();

// remove clip path
chart.internal.main.select('.' + c3.chart.internal.fn.CLASS.chart).attr('clip-path', null);

小提琴 - http://jsfiddle.net/b7ns8muv/

我删除了underscore.js函数调用。

以下是调整之前和之后的样子。请注意,从“之前”图表中取出clippath也可以更好地了解调整。

enter image description here