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

时间:2013-07-25 09:53:03

标签: extjs charts extjs4 extjs4.2

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

enter image description here

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

label : {
    rotate : {degrees:45}
}
图片下方的

是我的Sencha自定义图表。大多数Category标签都没有显示。

enter image description here

我正在考虑自定义onPlaceLabel功能,但我不知道该怎么做。 我将如何做到这一点来实现我所需要的?

2 个答案:

答案 0 :(得分:5)

你需要覆盖Ext.chart.axis.Axis#drawHoriztontalLabelsonPlaceLabel用于图表本身写的东西。就像栏顶部的标签一样,你明白我的意思吗?

干净的方法是override这个类,并实现一些快乐的选择。如果你想了解实现,我会让你探讨我在帖子末尾写的完整代码......

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
    }
});

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

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

    labelRows: 5,
    hideOverlappingLabels: false
}

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

enter image description here

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

enter image description here

因此,我使用了一个选项,可以修复标签行的数量,并在这些行之间均匀分布标签。我还添加了hideOverlappingLabels,确保即使我们错过运气并且某些标签结束重叠也不会丢失任何标签。

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

{
    // ...
    hideOverlappingLabels: false,
    labelRows: 5
}

enter image description here

我希望能够满足您的需求,或者至少可以根据您的需求提供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;
    }
});

答案 1 :(得分:0)

我遇到类似的问题,xaxis标签文本太长了。如果缩短可见标签文本并使用轴标签的工具提示是一个选项,那么您可能会发现以下有用...

我的解决方案是:

  1. 缩短可见轴标签文本,使标签适合(因此 渲染)

  2. 为轴标签精灵添加工具提示,并使其显示完整的标签文字

  3. 代码段:

    1. 内轴配置......

      label : {
             renderer: function(v){
      
              //if v is 'Grilled Pizza Special' then you get something like 'Grilled ...'
               return Ext.String.ellipsis(v,12);
             }                 
          }
      
    2. 修改了drawHorizo​​ntalLabels()...

      drawHorizontalLabels: function () {
      var me = this,
          labelConf = me.label,
          floor = Math.floor,
          max = Math.max,
          axes = me.chart.axes,
          insetPadding = me.chart.insetPadding,
          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,tooltipText,
          last, x, y, i, firstLabel;
      
      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++) {
          point = inflections[i];
          text = me.label.renderer(labels[i]);
          //not using text variable above for tooltip as tooltip would render the ellipsis text rather than the full label text.
          tooltipText = 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 && me.chart.maxGutter[0] == 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);
          }
      
          textLabel.setAttributes({
              hidden: false,
              x: x,
              y: y
          }, true);
      
                var labelTip = Ext.create('Ext.tip.ToolTip', {
              target : textLabel.el,
              html : tooltipText
          });
      
          // 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;
              }
          }
      
          prevLabel = textLabel;
          prevLabelId = i;
      }
      
      return maxHeight;
      }
      
相关问题