/**
* @private
*/
Ext.define('Ext.chart.legend.sprite.Item', {
extend: 'Ext.draw.sprite.Composite',
alias: 'sprite.legenditem',
type: 'legenditem',
isLegendItem: true,
requires: [
'Ext.draw.sprite.Text',
'Ext.draw.sprite.Circle'
],
inheritableStatics: {
def: {
processors: {
enabled: 'limited01',
markerLabelGap: 'number'
},
animationProcessors: {
enabled: null,
markerLabelGap: null
},
defaults: {
enabled: true,
markerLabelGap: 5
},
triggers: {
enabled: 'enabled',
markerLabelGap: 'layout'
},
updaters: {
layout: 'layoutUpdater',
enabled: 'enabledUpdater'
}
}
},
config: {
// Sprite's attributes are processed after initConfig.
// So we need to init below configs lazily, as otherwise
// adding sprites (created from those configs) to composite
// will result in an attempt to access attributes that
// composite doesn't have yet.
label: {
$value: {
type: 'text'
},
lazy: true
},
marker: {
$value: {
type: 'circle'
},
lazy: true
},
legend: null,
store: null,
record: null,
series: null
},
applyLabel: function(label, oldLabel) {
var sprite;
if (label) {
if (label.isSprite && label.type === 'text') {
sprite = label;
}
else {
if (oldLabel && label.type === oldLabel.type) {
oldLabel.setConfig(label);
sprite = oldLabel;
this.scheduleUpdater(this.attr, 'layout');
}
else {
sprite = new Ext.draw.sprite.Text(label);
}
}
}
return sprite;
},
defaultMarkerSize: 10,
updateLabel: function(label, oldLabel) {
var me = this;
me.removeSprite(oldLabel);
label.setAttributes({
textBaseline: 'middle'
});
me.addSprite(label);
me.scheduleUpdater(me.attr, 'layout');
},
applyMarker: function(config) {
var marker;
if (config) {
if (config.isSprite) {
marker = config;
}
else {
marker = this.createMarker(config);
}
}
marker = this.resetMarker(marker, config);
return marker;
},
createMarker: function(config) {
var marker;
// If marker attributes are animated, the attributes change over
// time from default values to the values specified in the marker
// config. But the 'legenditem' sprite needs final values
// to properly layout its children.
delete config.animation;
if (config.type === 'image') {
delete config.width;
delete config.height;
}
marker = Ext.create('sprite.' + config.type, config);
return marker;
},
resetMarker: function(sprite, config) {
var size = config.size || this.defaultMarkerSize,
bbox, max, scale;
// Layout may not work properly,
// if the marker sprite is transformed to begin with.
sprite.setTransform([1, 0, 0, 1, 0, 0], true);
if (config.type === 'image') {
sprite.setAttributes({
width: size,
height: size
});
}
else {
// This should work with any sprite, irrespective of what attribute
// is used to control sprite's size ('size', 'r', or something else).
// However, the 'image' sprite above is a special case.
bbox = sprite.getBBox();
max = Math.max(bbox.width, bbox.height);
scale = size / max;
sprite.setAttributes({
scalingX: scale,
scalingY: scale
});
}
return sprite;
},
updateMarker: function(marker, oldMarker) {
var me = this;
me.removeSprite(oldMarker);
me.addSprite(marker);
me.scheduleUpdater(me.attr, 'layout');
},
updateSurface: function(surface, oldSurface) {
var me = this;
me.callParent([surface, oldSurface]);
if (surface) {
me.scheduleUpdater(me.attr, 'layout');
}
},
enabledUpdater: function(attr) {
var marker = this.getMarker();
if (marker) {
marker.setAttributes({
globalAlpha: attr.enabled ? 1 : 0.3
});
}
},
layoutUpdater: function() {
var me = this,
attr = me.attr,
label = me.getLabel(),
marker = me.getMarker(),
labelBBox, markerBBox,
totalHeight;
// Measuring bounding boxes of transformed marker and label
// sprites and translating the sprites by required amount,
// makes layout virtually bullet-proof to unaccounted for
// changes in sprite attributes, whatever the sprite type may be.
markerBBox = marker.getBBox();
labelBBox = label.getBBox();
totalHeight = Math.max(markerBBox.height, labelBBox.height);
// Because we are getting an already transformed bounding box,
// we want to add to that transformation, not replace it,
// so setting translationX/Y attributes here would be inappropriate.
marker.transform([1, 0, 0, 1,
-markerBBox.x,
-markerBBox.y + (totalHeight - markerBBox.height) / 2
], true);
label.transform([1, 0, 0, 1,
-labelBBox.x + markerBBox.width + attr.markerLabelGap,
-labelBBox.y + (totalHeight - labelBBox.height) / 2
], true);
me.bboxUpdater(attr);
}
});