extjs-gpl
Version:
GPL licensed version of Sencha Ext JS
466 lines (429 loc) • 16 kB
JavaScript
/**
* Abstract class that provides default styles for non-specified things.
* Should be sub-classed when creating new themes.
* For example:
*
* Ext.define('Ext.chart.theme.Custom', {
* extend: 'Ext.chart.theme.Base',
* singleton: true,
* alias: 'chart.theme.custom',
* config: {
* baseColor: '#ff9f00'
* }
* });
*
* Theme provided values will not override the values provided in an instance config.
* However, if a theme provided value is an object, it will be merged with the value
* from the instance config, unless the theme provided object has a '$default' key
* set to 'true'.
*
* Certain chart theme configs (e.g. 'fontSize') may use the 'default' value to indicate
* that they should inherit a value from the corresponding CSS style provided by
* a framework theme. Additionally, one can use basic binary operators like multiplication,
* addition and subtraction to derive from the default value, e.g. fontSize: 'default*1.3'.
*
* Important: the theme should not use the 'font' shorthand to specify the font of labels
* and other text elements of a chart. Instead, individual font properties should be used:
* 'fontStyle', 'fontVariant', 'fontWeight', 'fontSize' and 'fontFamily'.
*/
Ext.define('Ext.chart.theme.Base', {
mixins: {
factoryable: 'Ext.mixin.Factoryable'
},
requires: ['Ext.draw.Color'],
factoryConfig: {
type: 'chart.theme'
},
isTheme: true,
config: {
/**
* @cfg {String/Ext.util.Color} baseColor
* The base color used to generate the {@link Ext.chart.AbstractChart#colors} of the theme.
*/
baseColor: null,
/**
* @cfg {Array} colors
*
* Array of colors/gradients to be used by the theme.
* Defaults to {@link #colorDefaults}.
*/
colors: undefined,
/**
* @cfg {Object} gradients
*
* The gradient config to be used by series' sprites. E.g.:
*
* {
* type: 'linear',
* degrees: 90
* }
*
* Please refer to the documentation for the {@link Ext.draw.gradient.Linear linear}
* and {@link Ext.draw.gradient.Radial radial} gradients for all possible options.
* The color {@link Ext.draw.gradient.Gradient#stops stops} for the gradients
* will be generated by the theme based on the {@link #colors} config.
*/
gradients: null,
/**
* @cfg {Object} chart
* Theme defaults for the chart.
* Can apply to all charts or just a specific type of chart.
* For example:
*
* chart: {
* defaults: {
* background: 'lightgray'
* },
* polar: {
* background: 'green'
* }
* }
*
* The values from the chart.defaults and chart.*type* configs (where *type* is a valid
* chart xtype, e.g. '{@link Ext.chart.CartesianChart cartesian}' or '{@link Ext.chart.PolarChart polar}')
* will be applied to corresponding chart configs.
* E.g., the chart.defaults.background config will set the {@link Ext.chart.AbstractChart#background}
* config of all charts, where the chart.cartesian.flipXY config will only set the
* {@link Ext.chart.CartesianChart#flipXY} config of all cartesian charts.
*/
chart: {
defaults: {
background: 'white'
}
},
/**
* @cfg {Object} axis
* Theme defaults for the axes.
* Can apply to all axes or only axes with a specific position.
* For example:
*
* axis: {
* defaults: {
* style: {strokeStyle: 'red'}
* },
* left: {
* title: {fillStyle: 'green'}
* }
* }
*
* The values from the axis.defaults and axis.*position* configs (where *position*
* is a valid axis {@link Ext.chart.axis.Axis#position}, e.g. 'bottom') will be
* applied to corresponding {@link Ext.chart.axis.Axis axis} configs.
* E.g., the axis.defaults.label config will apply to the {@link Ext.chart.axis.Axis#label}
* config of all axes, where the axis.left.titleMargin config will only apply to the
* {@link Ext.chart.axis.Axis#titleMargin} config of all axes positioned to the left.
*/
axis: {
defaults: {
label: {
x: 0,
y: 0,
textBaseline: 'middle',
textAlign: 'center',
fontSize: 'default',
fontFamily: 'default',
fontWeight: 'default',
fillStyle: 'black'
},
title: {
fillStyle: 'black',
fontSize: 'default*1.23',
fontFamily: 'default',
fontWeight: 'default'
},
style: {
strokeStyle: 'black'
},
grid: {
strokeStyle: 'rgb(221, 221, 221)'
}
},
top: {
style: {
textPadding: 5
}
},
bottom: {
style: {
textPadding: 5
}
}
},
/**
* @cfg {Object} series
* Theme defaults for the series.
* Can apply to all series or just a specific type of series.
* For example:
*
* series: {
* defaults: {
* style: {
* lineWidth: 2
* }
* },
* bar: {
* animation: {
* easing: 'bounceOut',
* duration: 1000
* }
* }
* }
*
* The values from the series.defaults and series.*type* configs (where *type*
* is a valid series {@link Ext.chart.series.Series#type}, e.g. 'line') will be
* applied to corresponding series configs.
* E.g., the series.defaults.label config will apply to the {@link Ext.chart.series.Series#label}
* config of all series, where the series.line.step config will only apply to the
* {@link Ext.chart.series.Line#step} config of {@link Ext.chart.series.Line line} series.
*/
series: {
defaults: {
label: {
fillStyle: 'black',
strokeStyle: 'none',
fontFamily: 'default',
fontWeight: 'default',
fontSize: 'default*1.077',
textBaseline: 'middle',
textAlign: 'center'
},
labelOverflowPadding: 5
}
},
/**
* @cfg {Object} sprites
* Default style for the custom chart sprites by type.
* For example:
*
* sprites: {
* text: {
* fontWeight: 300
* }
* }
*
* These sprite attribute overrides will apply to custom sprites of all charts
* specified using the {@link Ext.draw.Container#sprites} config.
* The overrides are specified by sprite type, e.g. sprites.text config
* tells to apply given attributes to all {@link Ext.draw.sprite.Text text} sprites.
*/
sprites: {
text: {
fontSize: 'default',
fontWeight: 'default',
fontFamily: 'default',
fillStyle: 'black'
}
},
/**
* Style information for the {Ext.chart.legend.SpriteLegend sprite legend}.
* If the {@link Ext.chart.legend.Legend DOM} legend is used, this config is ignored.
* For additional details see {@link Ext.chart.AbstractChart#legend}.
* @cfg {Object} legend
* @cfg {Ext.chart.legend.sprite.Item} legend.item
* @cfg {Object} legend.border See {@link Ext.chart.legend.SpriteLegend#border}.
*/
legend: {
label: {
fontSize: 14,
fontWeight: 'default',
fontFamily: 'default',
fillStyle: 'black'
},
border: {
lineWidth: 1,
radius: 4,
fillStyle: 'none',
strokeStyle: 'gray'
},
background: 'white'
},
/**
* @private
* An object with the following structure:
* {
* fillStyle: [color, color, ...],
* strokeStyle: [color, color, ...],
* ...
* }
* If missing, generated from the other configs: 'baseColor, 'gradients', 'colors'.
*/
seriesThemes: undefined,
markerThemes: {
type: ['circle', 'cross', 'plus', 'square', 'triangle', 'diamond']
},
/**
* @deprecated Use the {@link Ext.draw.Container#gradients} config instead.
* @since 5.0.1
*/
useGradients: false,
/**
* @deprecated Use the {@link Ext.chart.AbstractChart#background} config instead.
* @since 5.0.1
*/
background: null
},
colorDefaults: [ '#94ae0a', '#115fa6', '#a61120', '#ff8809', '#ffd13e', '#a61187', '#24ad9a', '#7c7474', '#a66111' ],
constructor: function (config) {
this.initConfig(config);
this.resolveDefaults();
},
defaultRegEx: /^default([+\-/\*]\d+(?:\.\d+)?)?$/,
defaultOperators: {
'*': function (v1, v2) {
return v1 * v2;
},
'+': function (v1, v2) {
return v1 + v2;
},
'-': function (v1, v2) {
return v1 - v2;
}
},
resolveDefaults: function () {
var me = this;
Ext.onReady(function () {
var sprites = Ext.clone(me.getSprites()),
legend = Ext.clone(me.getLegend()),
axis = Ext.clone(me.getAxis()),
series = Ext.clone(me.getSeries()),
div, key, config;
if (!me.superclass.defaults) {
div = Ext.getBody().createChild({tag: 'div', cls: 'x-component'});
me.superclass.defaults = {
fontFamily: div.getStyle('fontFamily'),
fontWeight: div.getStyle('fontWeight'),
fontSize: parseFloat(div.getStyle('fontSize')),
fontVariant: div.getStyle('fontVariant'),
fontStyle: div.getStyle('fontStyle')
};
div.destroy();
}
me.replaceDefaults(sprites.text);
me.setSprites(sprites);
me.replaceDefaults(legend.label);
me.setLegend(legend);
for (key in axis) {
config = axis[key];
me.replaceDefaults(config.label);
me.replaceDefaults(config.title);
}
me.setAxis(axis);
for (key in series) {
config = series[key];
me.replaceDefaults(config.label);
}
me.setSeries(series);
});
},
replaceDefaults: function (target) {
var me = this,
defaults = me.superclass.defaults,
defaultRegEx = me.defaultRegEx,
key, value, match, binaryFn;
if (Ext.isObject(target)) {
for (key in defaults) {
match = defaultRegEx.exec(target[key]);
if (match) {
value = defaults[key];
match = match[1];
if (match) {
binaryFn = me.defaultOperators[match.charAt(0)];
value = Math.round(binaryFn(value, parseFloat(match.substr(1))));
}
target[key] = value;
}
}
}
},
applyBaseColor: function (baseColor) {
var midColor, midL;
if (baseColor) {
midColor = baseColor.isColor ? baseColor : Ext.util.Color.fromString(baseColor);
midL = midColor.getHSL()[2];
if (midL < 0.15) {
midColor = midColor.createLighter(0.3);
} else if (midL < 0.3) {
midColor = midColor.createLighter(0.15);
} else if (midL > 0.85) {
midColor = midColor.createDarker(0.3);
} else if (midL > 0.7) {
midColor = midColor.createDarker(0.15);
}
this.setColors([
midColor.createDarker(0.3).toString(),
midColor.createDarker(0.15).toString(),
midColor.toString(),
midColor.createLighter(0.12).toString(),
midColor.createLighter(0.24).toString(),
midColor.createLighter(0.31).toString()
]);
}
return baseColor;
},
applyColors: function (newColors) {
return newColors || this.colorDefaults;
},
updateUseGradients: function (useGradients) {
if (useGradients) {
this.updateGradients({
type: 'linear',
degrees: 90
});
}
},
updateBackground: function (background) {
if (background) {
var chart = this.getChart();
chart.defaults.background = background;
this.setChart(chart);
}
},
updateGradients: function (gradients) {
var colors = this.getColors(),
items = [], gradient,
midColor, color,
i, ln;
if (Ext.isObject(gradients)) {
for (i = 0, ln = colors && colors.length || 0; i < ln; i++) {
midColor = Ext.util.Color.fromString(colors[i]);
if (midColor) {
color = midColor.createLighter(0.15).toString();
gradient = Ext.apply(Ext.Object.chain(gradients), {
stops: [
{
offset: 1,
color: midColor.toString()
},
{
offset: 0,
color: color.toString()
}
]
});
items.push(gradient);
}
}
this.setColors(items);
}
},
applySeriesThemes: function (newSeriesThemes) {
// Init the 'colors' config with solid colors generated from the 'baseColor'.
this.getBaseColor();
// Init the 'gradients' config with a hardcoded value, if the legacy 'useGradients'
// config was set to 'true'. This in turn updates the 'colors' config.
this.getUseGradients();
// Init the 'gradients' config normally. This also updates the 'colors' config.
this.getGradients();
var colors = this.getColors(); // Final colors.
if (!newSeriesThemes) {
newSeriesThemes = {
fillStyle: Ext.Array.clone(colors),
strokeStyle: Ext.Array.map(colors, function (value) {
var color = Ext.util.Color.fromString(value.stops ? value.stops[0].color : value);
return color.createDarker(0.15).toString();
})
};
}
return newSeriesThemes;
}
});