ExtJS5图表 - 扩展笛卡尔图表

时间:2015-02-11 13:47:55

标签: extjs configuration charts initialization extjs5

下面有两个例子(A和B)。第一个是核心工作,但图表由容器管理。我觉得这不是必要的。我想直接扩展Cartesian图表,而不是将其添加到 Container。我试图在第二个例子B中这样做,但我没有成功。

示例A

这个例子很好用。它源自Sencha's ExtJS5 Multi-axis column chart example of their kitchen sink

Demo @ JSFiddle

var climateData = getClimateData();

Ext.define('ChartApp.mixins.reader.DynamicReaderMixin', {
    extend : 'Ext.Mixin',

    readRecords : function(data) {
        var me = this;
        var rootData = data;
        console.log(data);        

        this.callParent(arguments);
    }
});

Ext.define('ChartApp.data.reader.DynamicChartReader', {
    extend : 'Ext.data.reader.Json',
    alias : 'widget.dynamicChartReader',
    xtype : 'dynamicChartReader',
    mixins : {
        dynamicReader : 'ChartApp.mixins.reader.DynamicReaderMixin'
    },
    config : {
        xField : null
    },

    readRecords : function(data) {
        console.log('Reading records...');

        if (data.metaData == null) {
            data = this.mixin.dynamicReader.readRecords.call(this, data);
        }

        return this.callParent([data]);
    }
});

Ext.define("ChartApp.model.Climate", {
    extend: "Ext.data.Model",
    fields: ["month", "high", "low", {
        name: "highF",
        calculate: function (b) {
            return toFaherenheit(b.high);
        }
    }, {
        name: "lowF",
        calculate: function (b) {
            return toFaherenheit(b.low);
        }
    }],    
});

Ext.define("ChartApp.store.Climate", {
    extend: "Ext.data.Store",
    alias: "store.climate",
    model : "ChartApp.model.Climate",
    counter: 0,
    generateData: function () {
        var h = this.config.data,
            e, j, g = [];
        for (e = 0; e < h.length; e++) {
            g.push({
                month: h[e].month,
                high: 20 + Math.random() * 20,
                low: Math.random() * 20
            })
        }
        return g
    },
    refreshData: function () {
        this.setData(this.generateData())
    }
});

Ext.define('ChartApp.view.charts.column.MultiAxis', {
    extend: 'Ext.container.Container',
    xtype: 'column-multi-axis',

    width: 650,
    height: 500,

    initComponent: function () {
        var me = this;

        var highSeries = {
            type: 'line',
            xField: 'month',
            yField: ['highF'],
            yAxis: 'fahrenheit-axis',
            style: {
                lineWidth: 2,
                fillStyle: '#115fa6',
                strokeStyle: '#115fa6',
                fillOpacity: 0.6,
                miterLimit: 3,
                lineCap: 'miter'
            },
            colors : [ '#115fa6' ],
            title : ['High'],
            tooltip: {
                trackMouse: true,
                style: 'background: #444; color: #FFF',
                renderer: function(storeItem, item) {
                    var title = item.series.getTitle()[0];
                    this.setHtml(title + ' for '
                        + storeItem.get('month') + ': ' 
                        + storeItem.get(item.field).toFixed(2) + '°');
                }
            }
        },
        lowSeries = Ext.apply({}, {
            yField: ['lowF'],
            style: {
                lineWidth: 2,
                fillStyle: '#ff8800',
                strokeStyle: '#884400',
                fillOpacity: 0.6,
                miterLimit: 3,
                lineCap: 'miter'
            },
            colors : [ '#ff8800' ],
            title : ['Low'],
        }, highSeries);

        me.items = [{
            xtype: 'cartesian',
            legend : {
                hidden : true
            },
            store: {
                type: 'climate',
                reader: {
                    xtype : 'dynamicChartReader'
                }
            },
            insetPadding: 10,
            innerPadding: {
                left: 20,
                right: 20
            },
            interactions: 'crosszoom',
            axes: [{
                type: 'numeric',
                id: 'fahrenheit-axis',
                adjustByMajorUnit: true,
                position: 'left',
                titleMargin: 20,
                minimum: 32,
                grid: true,
                title: {
                    text: 'Temperature in °F',
                    fontSize: 14
                },
                listeners: {
                    rangechange: function (range) {
                        var cAxis = this.getChart().getAxis('celsius-axis');
                        if (cAxis) {
                            cAxis.setMinimum(toCelcius(range[0]));
                            cAxis.setMaximum(toCelcius(range[1]));
                        }
                    }
                }
            }, {
                id: 'celsius-axis',
                type: 'numeric',
                titleMargin: 20,
                position: 'right',
                title: {
                    text: 'Temperature in °C',
                    fontSize: 14,
                    fillStyle: 'red'
                }
            }, {
                id: 'months-axis',
                type: 'category',
                position: 'bottom',
                title: {
                    text: 'Months'
                }
            }, {
                position: 'top',
                linkedTo: 'months-axis',
                title: {
                    text: 'Climate data for Redwood City, California',
                    fontSize: 16,
                    fillStyle: 'green'
                },
                titleMargin: 20
            }],
            series: [ highSeries, lowSeries ]
        }];

        this.callParent();
    },

    getChart : function() {
        return this.down('cartesian');
    },

    getStore : function() {
        return this.getChart().getStore();
    },

    getLegendStore : function() {
        return this.getChart().getLegendStore();
    }
});

Ext.define('ChartApp.chart.Legend', {
    extend : 'Ext.chart.Legend',
    xtype: 'extendedlegend',
    docked : 'left',

    tpl: [
        '<div class="', Ext.baseCSSPrefix, 'legend-container">',
        '<tpl for=".">',
        '<div class="', Ext.baseCSSPrefix, 'legend-item">',
        '<input type="checkbox" class="', Ext.baseCSSPrefix, 'legend-item-check" checked="true" />',
        '<span ',
        'class="', Ext.baseCSSPrefix,
        'legend-item-marker {[ values.disabled ? Ext.baseCSSPrefix + \'legend-inactive\' : \'\' ]}" ',
        'style="background:{mark};">',
        '</span>{name}',
        '</div>',
        '</tpl>',
        '</div>'
    ],

    initComponent : function() {
        var me = this;

        me.callParent(arguments);
    },

    onItemClick: function (record, item, index, e) {
        var target = e.getTarget();
        var disabled = record.get('disabled');

        if (this.isCheckBox(target)) {
            target.checked = !disabled;
            console.log(target.checked);
            this.callParent(arguments);
        }
    },

    isCheckBox : function(element) {
        return element && element.tagName.toLowerCase() === 'input' && element.type === 'checkbox';
    }
});

Ext.define('ChartApp.components.ChartContainer', {
    extend : 'Ext.container.Container',
    alias : 'widget.chartcontainer',
    referenceHolder: true,
    height : 600,
    width : 800,
    layout: 'border',
    items: [{
        region : 'west',
        title : 'Legend',
        items : [{
            xtype : 'extendedlegend',
            reference : 'chartLegend',
        }],
        width : 180,
        minHeight : 550,
        collapsible : true,
        collasped : false,
        split : true,
        animCollapse : true
    }, {
        region : 'center',
        reference : 'chartWrapper',
        layout : 'fit',
        margins : '5 5 0 0',
        items : [{
            xtype : 'column-multi-axis',
            reference : 'chart',
            layout : 'fit'
        }]
    }],

    initComponent : function() {
        var me = this;

        me.callParent(arguments);

        var chart = me.lookupReference('chart');
        chart.getStore().loadData(climateData);

        var legend = me.lookupReference('chartLegend');
        legend.setStore(chart.getLegendStore());
    }
});

Ext.onReady(function() {
    Ext.create('Ext.panel.Panel', {
        title : 'Dual Axis Example',
        layout : 'fit',
        items : [{
            xtype : 'chartcontainer'
        }],
        renderTo: Ext.getBody(),
    });
});

function toCelcius(faherenheit) {
    return (faherenheit - 32) / 1.8;
};

function toFaherenheit(celcius) {
    return (celcius * 1.8) + 32;
};

function getClimateData() {
    return [
        { month: "Jan", high: 14.7, low: 5.6 },
        { month: "Feb", high: 16.5, low: 6.6 },
        { month: "Mar", high: 18.6, low: 7.3 },
        { month: "Apr", high: 20.8, low: 8.1 },
        { month: "May", high: 23.3, low: 9.9 },
        { month: "Jun", high: 26.2, low: 11.9 },
        { month: "Jul", high: 27.7, low: 13.3 },
        { month: "Aug", high: 27.6, low: 13.2 },
        { month: "Sep", high: 26.4, low: 12.1 },
        { month: "Oct", high: 23.6, low: 9.9 },
        { month: "Nov", high: 17.0, low: 6.8 },
        { month: "Dec", high: 14.7, low: 5.8 }
    ];
}

例B

在此示例中,column-multi-axis直接扩展了cartesian图表。由于某些原因,我在chartcontainer initComponent this.callParent()调用var climateData = getClimateData(); Ext.define('ChartApp.mixins.reader.DynamicReaderMixin', { extend : 'Ext.Mixin', readRecords : function(data) { var me = this; var rootData = data; console.log(data); this.callParent(arguments); } }); Ext.define('ChartApp.data.reader.DynamicChartReader', { extend : 'Ext.data.reader.Json', alias : 'widget.dynamicChartReader', xtype : 'dynamicChartReader', mixins : { dynamicReader : 'ChartApp.mixins.reader.DynamicReaderMixin' }, config : { xField : null }, readRecords : function(data) { console.log('Reading records...'); if (data.metaData == null) { data = this.mixin.dynamicReader.readRecords.call(this, data); } return this.callParent([data]); } }); Ext.define("ChartApp.model.Climate", { extend: "Ext.data.Model", fields: ["month", "high", "low", { name: "highF", calculate: function (b) { return toFaherenheit(b.high); } }, { name: "lowF", calculate: function (b) { return toFaherenheit(b.low); } }], }); Ext.define("ChartApp.store.Climate", { extend: "Ext.data.Store", alias: "store.climate", model : "ChartApp.model.Climate", counter: 0, generateData: function () { var h = this.config.data, e, j, g = []; for (e = 0; e < h.length; e++) { g.push({ month: h[e].month, high: 20 + Math.random() * 20, low: Math.random() * 20 }) } return g }, refreshData: function () { this.setData(this.generateData()) } }); Ext.define('ChartApp.view.charts.column.MultiAxis', { extend: 'Ext.chart.CartesianChart', xtype: 'column-multi-axis', width: 650, height: 500, initComponent: function () { var me = this; var highSeries = { type: 'line', xField: 'month', yField: ['highF'], yAxis: 'fahrenheit-axis', style: { lineWidth: 2, fillStyle: '#115fa6', strokeStyle: '#115fa6', fillOpacity: 0.6, miterLimit: 3, lineCap: 'miter' }, colors : [ '#115fa6' ], title : ['High'], tooltip: { trackMouse: true, style: 'background: #444; color: #FFF', renderer: function(storeItem, item) { var title = item.series.getTitle()[0]; this.setHtml(title + ' for ' + storeItem.get('month') + ': ' + storeItem.get(item.field).toFixed(2) + '°'); } } }, lowSeries = Ext.apply({}, { yField: ['lowF'], style: { lineWidth: 2, fillStyle: '#ff8800', strokeStyle: '#884400', fillOpacity: 0.6, miterLimit: 3, lineCap: 'miter' }, colors : [ '#ff8800' ], title : ['Low'], }, highSeries); Ext.apply(me, { legend : { hidden : true }, store: { type: 'climate', reader: { xtype : 'dynamicChartReader' } }, insetPadding: 10, innerPadding: { left: 20, right: 20 }, interactions: 'crosszoom', axes: [{ type: 'numeric', id: 'fahrenheit-axis', adjustByMajorUnit: true, position: 'left', titleMargin: 20, minimum: 32, grid: true, title: { text: 'Temperature in °F', fontSize: 14 }, listeners: { rangechange: function (range) { var cAxis = this.getChart().getAxis('celsius-axis'); if (cAxis) { cAxis.setMinimum(toCelcius(range[0])); cAxis.setMaximum(toCelcius(range[1])); } } } }, { id: 'celsius-axis', type: 'numeric', titleMargin: 20, position: 'right', title: { text: 'Temperature in °C', fontSize: 14, fillStyle: 'red' } }, { id: 'months-axis', type: 'category', position: 'bottom', title: { text: 'Months' } }, { position: 'top', linkedTo: 'months-axis', title: { text: 'Climate data for Redwood City, California', fontSize: 16, fillStyle: 'green' }, titleMargin: 20 }], series: [ highSeries, lowSeries ] }); this.callParent(); } }); Ext.define('ChartApp.chart.Legend', { extend : 'Ext.chart.Legend', xtype: 'extendedlegend', docked : 'left', tpl: [ '<div class="', Ext.baseCSSPrefix, 'legend-container">', '<tpl for=".">', '<div class="', Ext.baseCSSPrefix, 'legend-item">', '<input type="checkbox" class="', Ext.baseCSSPrefix, 'legend-item-check" checked="true" />', '<span ', 'class="', Ext.baseCSSPrefix, 'legend-item-marker {[ values.disabled ? Ext.baseCSSPrefix + \'legend-inactive\' : \'\' ]}" ', 'style="background:{mark};">', '</span>{name}', '</div>', '</tpl>', '</div>' ], initComponent : function() { var me = this; me.callParent(arguments); }, onItemClick: function (record, item, index, e) { var target = e.getTarget(); var disabled = record.get('disabled'); if (this.isCheckBox(target)) { target.checked = !disabled; console.log(target.checked); this.callParent(arguments); } }, isCheckBox : function(element) { return element && element.tagName.toLowerCase() === 'input' && element.type === 'checkbox'; } }); Ext.define('ChartApp.components.ChartContainer', { extend : 'Ext.container.Container', alias : 'widget.chartcontainer', referenceHolder: true, height : 600, width : 800, layout: 'border', items: [{ region : 'west', title : 'Legend', items : [{ xtype : 'extendedlegend', reference : 'chartLegend', }], width : 180, minHeight : 550, collapsible : true, collasped : false, split : true, animCollapse : true }, { region : 'center', reference : 'chartWrapper', layout : 'fit', margins : '5 5 0 0', items : [{ xtype : 'column-multi-axis', reference : 'chart', layout : 'fit' }] }], initComponent : function() { var me = this; me.callParent(arguments); var chart = me.lookupReference('chart'); console.log(chart.getStore()); // Still a config chart.getStore().loadData(climateData); var legend = me.lookupReference('chartLegend'); legend.setStore(chart.getLegendStore()); } }); Ext.onReady(function() { Ext.create('Ext.panel.Panel', { title : 'Dual Axis Example', layout : 'fit', items : [{ xtype : 'chartcontainer' }], renderTo: Ext.getBody(), }); }); function toCelcius(faherenheit) { return (faherenheit - 32) / 1.8; }; function toFaherenheit(celcius) { return (celcius * 1.8) + 32; }; function getClimateData() { return [ { month: "Jan", high: 14.7, low: 5.6 }, { month: "Feb", high: 16.5, low: 6.6 }, { month: "Mar", high: 18.6, low: 7.3 }, { month: "Apr", high: 20.8, low: 8.1 }, { month: "May", high: 23.3, low: 9.9 }, { month: "Jun", high: 26.2, low: 11.9 }, { month: "Jul", high: 27.7, low: 13.3 }, { month: "Aug", high: 27.6, low: 13.2 }, { month: "Sep", high: 26.4, low: 12.1 }, { month: "Oct", high: 23.6, low: 9.9 }, { month: "Nov", high: 17.0, low: 6.8 }, { month: "Dec", high: 14.7, low: 5.8 } ]; } 之后未知,商店仍然是图表上的配置。

Demo @ JSFiddle

{{1}}

1 个答案:

答案 0 :(得分:0)

此时商店尚不存在 - 更好的说法还没有尝试运行setStore()。如果您真的需要它,请尝试致电:

chart.setStore(chart.getStore());

这应该调用负责商店创建的底层setter方法。