Sencha Ext JS 4图表:自定义xField(类别)标签位置

wen*_*ens 1 charts extjs extjs4 extjs4.2

我正在尝试将应用程序移植Flex 3Sencha Ext JS 4.此应用程序有一个带有柱形图的仪表板(请看下面的第一张图).它的值xField有点长文本.

在此输入图像描述

尽可能地,我不希望我的标签被旋转.好吧,我认为这有点混乱.如果可能的话,我希望我的标签在不适合的情况下交替定位.

label : {
    rotate : {degrees:45}
}
Run Code Online (Sandbox Code Playgroud)

下图是我的Sencha自定义图表.大部分Category标签都没有显示.

在此输入图像描述

我正在考虑自定义onPlaceLabel功能,但我不知道如何这样做.我该怎么做才能实现我所需要的?

rix*_*ixo 5

Ext.chart.axis.Axis#drawHoriztontalLabels是你需要覆盖的.onPlaceLabel是为了图表本身写的东西.就像酒吧顶部的标签一样,你明白我的意思吗?

干净的方法是覆盖类并实现一些快乐的选项.如果你想了解实现,我会让你探索我在帖子末尾提供的完整代码......

Ext.define('Ext.ux.chart.axis.Axis.OverlappingLabelOptions', {
    override: 'Ext.chart.axis.Axis'

    ,labelRows: 1

    ,hideOverlappingLabels: true

    ,drawHorizontalLabels: function() {
        // ... see at the end of the post for the full implementation
    }
});
Run Code Online (Sandbox Code Playgroud)

使用后包含此覆盖类后require,可以在轴定义中使用这两个选项.例如:

{
    type: 'Category',
    position: 'bottom',
    fields: ['name'],
    title: 'Sample Metrics',

    labelRows: 5,
    hideOverlappingLabels: false
}
Run Code Online (Sandbox Code Playgroud)

我的第一次尝试是将重叠标签自动推到一行.这就是你通过设置获得的labelRows: 'auto'.它在某些条件下运行良好,并具有自动化的优点.

在此输入图像描述

不幸的是,它可能变得非常混乱:

在此输入图像描述

因此,我尝试使用一个选项来修复标签行的数量,并在这些行之间均匀分布标签.我还补充hideOverlappingLabels说,即使我们错过运气并且某些标签结束重叠,也确保不会丢失任何标签.

以下是您使用此配置获得的信息:

{
    // ...
    hideOverlappingLabels: false,
    labelRows: 5
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

我希望能够满足您的需求,或者至少可以根据您的需求改进Ext的代码!

全面实施

/**
 * This override adds a {@link #labelRows} option to draw horizontal axis labels on multiple
 * rows, and also an {@link #hideOverlappingLabels} option.
 */
Ext.define('Ext.ux.chart.axis.Axis.OverlappingLabelOptions', {
    override: 'Ext.chart.axis.Axis'

    ,alternateClassName: 'Ext.ux.AxisOverlappingLabelOptions'

    /**
     * @cfg {Integer/String}
     *
     * Number of label rows. If this option is set to 'auto', then overlapping labels will
     * be drawn on the next row where they don't overlap. Which can give a messy result.
     */
    ,labelRows: 1

    /**
     * @cfg {Boolean}
     *
     * Set to false to prevent automatic hiding of overlapping labels.
     */
    ,hideOverlappingLabels: true

    ,drawHorizontalLabels: function() {
        var me = this,
            labelConf = me.label,
            floor = Math.floor,
            max = Math.max,
            axes = me.chart.axes,
            insetPadding = me.chart.insetPadding,
            gutters = me.chart.maxGutters,
            position = me.position,
            inflections = me.inflections,
            ln = inflections.length,
            labels = me.labels,
            maxHeight = 0,
            ratio,
            bbox, point, prevLabel, prevLabelId,
            adjustEnd = me.adjustEnd,
            hasLeft = axes.findIndex('position', 'left') != -1,
            hasRight = axes.findIndex('position', 'right') != -1,
            textLabel, text,
            last, x, y, i, firstLabel;

        var labelRows = Ext.num(this.labelRows, 1),
            autoOffsetLabels = this.labelRows === 'auto',
            hideLabels = this.hideOverlappingLabels;

        var lastLabelOnRow = [],
            row, j;

        last = ln - 1;
        //get a reference to the first text label dimensions
        point = inflections[0];
        firstLabel = me.getOrCreateLabel(0, me.label.renderer(labels[0]));
        ratio = Math.floor(Math.abs(Math.sin(labelConf.rotate && (labelConf.rotate.degrees * Math.PI / 180) || 0)));

        for (i = 0; i < ln; i++) {
            row = 0; // rx: start at first row
            point = inflections[i];
            text = me.label.renderer(labels[i]);
            textLabel = me.getOrCreateLabel(i, text);
            bbox = textLabel._bbox;
            //maxHeight = max(maxHeight, bbox.height + me.dashSize + me.label.padding);
            x = floor(point[0] - (ratio ? bbox.height : bbox.width) / 2);
            if (adjustEnd && gutters.left == 0 && gutters.right == 0) {
                if (i == 0 && !hasLeft) {
                    x = point[0];
                }
                else if (i == last && !hasRight) {
                    x = Math.min(x, point[0] - bbox.width + insetPadding);
                }
            }
            if (position == 'top') {
                y = point[1] - (me.dashSize * 2) - me.label.padding - (bbox.height / 2);
            }
            else {
                y = point[1] + (me.dashSize * 2) + me.label.padding + (bbox.height / 2);
            }

            // rx: vertical offset
            y += (i % labelRows) * bbox.height;

            textLabel.setAttributes({
                hidden: false,
                x: x,
                y: y
            }, true);

            if (autoOffsetLabels) {
                // rx: find the row on which we can draw the label without overlapping
                for (j=0; j<lastLabelOnRow.length; j++) {
                    if (me.intersect(textLabel, lastLabelOnRow[j])) {
                        row++;
                        textLabel.setAttributes({
                            y: y + row * bbox.height
                        }, true);
                    }
                }

                // rx: calc maxHeight knowing the row
                maxHeight = max(maxHeight, bbox.height + me.dashSize + me.label.padding + (bbox.height * row));

                // rx: keep reference to know where we can place the next label
                lastLabelOnRow[row] = textLabel;
            } else {

                if (hideLabels) {
                    // Skip label if there isn't available minimum space
                    if (i != 0 && (me.intersect(textLabel, prevLabel)
                        || me.intersect(textLabel, firstLabel))) {
                        if (i === last && prevLabelId !== 0) {
                            prevLabel.hide(true);
                        } else {
                            textLabel.hide(true);
                            continue;
                        }
                    }
                }

                maxHeight = max(maxHeight, bbox.height + me.dashSize + me.label.padding + bbox.height * (i % labelRows));
            }

            prevLabel = textLabel;
            prevLabelId = i;
        }

        return maxHeight;
    }
});
Run Code Online (Sandbox Code Playgroud)