ExtJS - столбчатая диаграмма с условной раскраской - PullRequest
6 голосов
/ 28 апреля 2011

EXTJS 4 - Я пытаюсь настроить функцию рендеринга для «серии» в StackedBarChart.Я хочу условно раскрасить бары.

renderer: function(sprite, record, curAttr, index, store) {
                        return Ext.apply(curAttr, {
                              fill: color
                        });
                        return curAttr;
},

Мой вопрос заключается в том, как узнать, какой элемент отображается в данный момент.Я хочу дать белый цвет первому элементу каждой записи в моем хранилище данных / серии.

Спасибо.

Ответы [ 2 ]

2 голосов
/ 25 июня 2012

Я нашел способ точно определить, какой элемент отображается в данный момент.Во-первых, вам понадобится следующее переопределение, которое решает несколько проблем с параметрами рендеринга .Это не должно повлиять на нормальные гистограммы, но я не проверял их.

Ext.override(Ext.chart.series.Bar,{
    drawSeries: function() {
        var me = this,
            chart = me.chart,
            store = chart.getChartStore(),
            surface = chart.surface,
            animate = chart.animate,
            stacked = me.stacked,
            column = me.column,
            enableShadows = chart.shadow,
            shadowGroups = me.shadowGroups,
            shadowGroupsLn = shadowGroups.length,
            group = me.group,
            seriesStyle = me.seriesStyle,
            items, ln, i, j, baseAttrs, sprite, rendererAttributes, shadowIndex, shadowGroup,
            bounds, endSeriesStyle, barAttr, attrs, anim;

        // ---- start edit ----
        var currentCol, currentStoreIndex;
        // ---- end edit ----


        if (!store || !store.getCount()) {
            return;
        }

        //fill colors are taken from the colors array.
        delete seriesStyle.fill;
        endSeriesStyle = Ext.apply(seriesStyle, this.style);
        me.unHighlightItem();
        me.cleanHighlights();

        me.getPaths();
        bounds = me.bounds;
        items = me.items;

        baseAttrs = column ? {
            y: bounds.zero,
            height: 0
        } : {
            x: bounds.zero,
            width: 0
        };
        ln = items.length;
        // Create new or reuse sprites and animate/display
        for (i = 0; i < ln; i++) {
            sprite = group.getAt(i);
            barAttr = items[i].attr;

            if (enableShadows) {
                items[i].shadows = me.renderShadows(i, barAttr, baseAttrs, bounds);
            }

            // ---- start edit ----
            if (stacked && items[i].storeItem.index != currentStoreIndex) {
              //console.log("i: %o, barsLen: %o, j: %o, items[i]: %o",i,bounds.barsLen,i / bounds.barsLen,items[i]);
              currentStoreIndex = items[i].storeItem.index;
              currentCol = 0;
            }
            else {
              ++currentCol;
            }
            // ---- end edit ----

            // Create a new sprite if needed (no height)
            if (!sprite) {
                attrs = Ext.apply({}, baseAttrs, barAttr);
                attrs = Ext.apply(attrs, endSeriesStyle || {});
                sprite = surface.add(Ext.apply({}, {
                    type: 'rect',
                    group: group
                }, attrs));
            }
            if (animate) {
                // ---- start edit ----
                rendererAttributes = me.renderer(sprite, items[i].storeItem, barAttr, (stacked? currentStoreIndex : i), store, (stacked? currentCol : undefined));
                // ---- end edit ----
                sprite._to = rendererAttributes;
                anim = me.onAnimate(sprite, { to: Ext.apply(rendererAttributes, endSeriesStyle) });
                if (enableShadows && stacked && (i % bounds.barsLen === 0)) {
                    j = i / bounds.barsLen;
                    for (shadowIndex = 0; shadowIndex < shadowGroupsLn; shadowIndex++) {
                        anim.on('afteranimate', function() {
                            this.show(true);
                        }, shadowGroups[shadowIndex].getAt(j));
                    }
                }
            }
            else {
                // ---- start edit ----
                rendererAttributes = me.renderer(sprite, items[i].storeItem, Ext.apply(barAttr, { hidden: false }), (stacked? currentStoreIndex : i), store, (stacked? currentCol : undefined));
                // ---- end edit ----
                sprite.setAttributes(Ext.apply(rendererAttributes, endSeriesStyle), true);
            }
            items[i].sprite = sprite;
        }

        // Hide unused sprites
        ln = group.getCount();
        for (j = i; j < ln; j++) {
            group.getAt(j).hide(true);
        }
        // Hide unused shadows
        if (enableShadows) {
            for (shadowIndex = 0; shadowIndex < shadowGroupsLn; shadowIndex++) {
                shadowGroup = shadowGroups[shadowIndex];
                ln = shadowGroup.getCount();
                for (j = i; j < ln; j++) {
                    shadowGroup.getAt(j).hide(true);
                }
            }
        }
        me.renderLabels();
    }
});

Вот список изменений для renderer():

  • Второй параметр теперьсопоставленный с правильным элементом магазина
  • Четвертый параметр теперь является индексом магазина вместо внутреннего номера элемента (бесполезно в противном случае IMO)
  • Добавлен шестой параметр, который сообщает текущий индекс сегмента в пределахзапись, не считая других свойств в записи, которые не принадлежат оси.
    Пример: для записи, которая выглядит как {name: 'metric': segment1: 12, segment2: 22}, индекс для segment1 будет 0 вместо 1,потому что первый элемент в записи не принадлежит его оси (это название категории)

Итак, чтобы ответить на ваш вопрос, теперь вы можете использовать средство рендеринга следующим образом:

renderer: function(sprite, record, attr, storeIndex, store, col) {
    // set the color to white for the first item in every record
    return (col == 0)? Ext.apply(attr, { fill: '#fff' }) : attr;
}

Если вы хотите установить цвет для именованного элемента, вы также можете сделать это следующим образом:

// let's say that every record looks like this:
// {name: 'metric one', user1: 23, user2: 50, user3: 10}

renderer: function(sprite, record, attr, storeIndex, store, col) {
    // retrieve the segment property name from the record using its numeric index.
    // remember that 'col' doesn't take into account other fields that don't
    // belong to the axis, so in this case we have to add 1 to the index
    var uid = Ext.Object.getAt(record.data, col+1)[0];

    // set the color to red for 'user2'
    return (uid == 'user2')? Ext.apply(attr, { fill: '#f00' }) : attr;
}

Для этого последнего вам понадобится эта функция, которая позволяет вам получитьсвойство объекта с помощьючисловой индекс:

/**
 * Returns the key and its value at the idx position
 * @return {Array} Array containing [key, value] or null
 */
Ext.Object.getAt = function(obj, idx) {
    var keys = Ext.Object.getKeys(obj);
    if (idx < keys.length) {
        return [keys[idx],obj[keys[idx]]];
    }
    return null;
}
2 голосов
/ 17 июня 2011

Индекс говорит вам, какой элемент рендеринга.Однако я заметил, что в некоторых ситуациях renderer () вызывается 3 раза, прежде чем элементы начинают обрабатываться.Я спрашивал об этом на форумах Сенчи, но безрезультатно.

...