/*
This file is part of Ext JS 4.2
Copyright (c) 2011-2013 Sencha Inc
Contact: http://www.sencha.com/contact
GNU General Public License Usage
This file may be used under the terms of the GNU General Public License version 3.0 as
published by the Free Software Foundation and appearing in the file LICENSE included in the
packaging of this file.
Please review the following information to ensure the GNU General Public License version 3.0
requirements will be met: http://www.gnu.org/copyleft/gpl.html.
If you are unsure which license is appropriate for your use, please contact the sales department
at http://www.sencha.com/contact.
Build date: 2013-05-16 14:36:50 (f9be68accb407158ba2b1be2c226a6ce1f649314)
*/
/**
* Provides specific methods to draw with VML.
*/
Ext.define('Ext.draw.engine.Vml', {
/* Begin Definitions */
extend: 'Ext.draw.Surface',
requires: ['Ext.draw.Draw', 'Ext.draw.Color', 'Ext.draw.Sprite', 'Ext.draw.Matrix', 'Ext.Element'],
/* End Definitions */
engine: 'Vml',
map: {M: "m", L: "l", C: "c", Z: "x", m: "t", l: "r", c: "v", z: "x"},
bitesRe: /([clmz]),?([^clmz]*)/gi,
valRe: /-?[^,\s\-]+/g,
fillUrlRe: /^url\(\s*['"]?([^\)]+?)['"]?\s*\)$/i,
pathlike: /^(path|rect)$/,
NonVmlPathRe: /[ahqstv]/ig, // Non-VML Pathing ops
partialPathRe: /[clmz]/g,
fontFamilyRe: /^['"]+|['"]+$/g,
baseVmlCls: Ext.baseCSSPrefix + 'vml-base',
vmlGroupCls: Ext.baseCSSPrefix + 'vml-group',
spriteCls: Ext.baseCSSPrefix + 'vml-sprite',
measureSpanCls: Ext.baseCSSPrefix + 'vml-measure-span',
zoom: 21600,
coordsize: 1000,
coordorigin: '0 0',
zIndexShift: 0,
// VML uses CSS z-index and therefore doesn't need sprites to be kept in zIndex order
orderSpritesByZIndex: false,
// @private
// Convert an SVG standard path into a VML path
path2vml: function (path) {
var me = this,
nonVML = me.NonVmlPathRe,
map = me.map,
val = me.valRe,
zoom = me.zoom,
bites = me.bitesRe,
command = Ext.Function.bind(Ext.draw.Draw.pathToAbsolute, Ext.draw.Draw),
res, pa, p, r, i, ii, j, jj;
if (String(path).match(nonVML)) {
command = Ext.Function.bind(Ext.draw.Draw.path2curve, Ext.draw.Draw);
} else if (!String(path).match(me.partialPathRe)) {
res = String(path).replace(bites, function (all, command, args) {
var vals = [],
isMove = command.toLowerCase() == "m",
res = map[command];
args.replace(val, function (value) {
if (isMove && vals.length === 2) {
res += vals + map[command == "m" ? "l" : "L"];
vals = [];
}
vals.push(Math.round(value * zoom));
});
return res + vals;
});
return res;
}
pa = command(path);
res = [];
for (i = 0, ii = pa.length; i < ii; i++) {
p = pa[i];
r = pa[i][0].toLowerCase();
if (r == "z") {
r = "x";
}
for (j = 1, jj = p.length; j < jj; j++) {
r += Math.round(p[j] * me.zoom) + (j != jj - 1 ? "," : "");
}
res.push(r);
}
return res.join(" ");
},
// @private - set of attributes which need to be translated from the sprite API to the native browser API
translateAttrs: {
radius: "r",
radiusX: "rx",
radiusY: "ry",
lineWidth: "stroke-width",
fillOpacity: "fill-opacity",
strokeOpacity: "stroke-opacity",
strokeLinejoin: "stroke-linejoin"
},
// @private - Minimun set of defaults for different types of sprites.
minDefaults: {
circle: {
fill: "none",
stroke: null,
"stroke-width": null,
opacity: null,
"fill-opacity": null,
"stroke-opacity": null
},
ellipse: {
cx: 0,
cy: 0,
rx: 0,
ry: 0,
fill: "none",
stroke: null,
"stroke-width": null,
opacity: null,
"fill-opacity": null,
"stroke-opacity": null
},
rect: {
x: 0,
y: 0,
width: 0,
height: 0,
rx: 0,
ry: 0,
fill: "none",
stroke: null,
"stroke-width": null,
opacity: null,
"fill-opacity": null,
"stroke-opacity": null
},
text: {
x: 0,
y: 0,
"text-anchor": "start",
font: '10px "Arial"',
fill: "#000",
stroke: null,
"stroke-width": null,
opacity: null,
"fill-opacity": null,
"stroke-opacity": null
},
path: {
d: "M0,0",
fill: "none",
stroke: null,
"stroke-width": null,
opacity: null,
"fill-opacity": null,
"stroke-opacity": null
},
image: {
x: 0,
y: 0,
width: 0,
height: 0,
preserveAspectRatio: "none",
opacity: null
}
},
// private
onMouseEnter: function (e) {
this.fireEvent("mouseenter", e);
},
// private
onMouseLeave: function (e) {
this.fireEvent("mouseleave", e);
},
// @private - Normalize a delegated single event from the main container to each sprite and sprite group
processEvent: function (name, e) {
var target = e.getTarget(),
surface = this.surface,
sprite;
this.fireEvent(name, e);
sprite = this.items.get(target.id);
if (sprite) {
sprite.fireEvent(name, sprite, e);
}
},
// Create the VML element/elements and append them to the DOM
createSpriteElement: function (sprite) {
var me = this,
attr = sprite.attr,
type = sprite.type,
zoom = me.zoom,
vml = sprite.vml || (sprite.vml = {}),
round = Math.round,
el = (type === 'image') ? me.createNode('image') : me.createNode('shape'),
path, skew, textPath;
el.coordsize = zoom + ' ' + zoom;
el.coordorigin = attr.coordorigin || "0 0";
Ext.get(el).addCls(me.spriteCls);
if (type == "text") {
vml.path = path = me.createNode("path");
path.textpathok = true;
vml.textpath = textPath = me.createNode("textpath");
textPath.on = true;
el.appendChild(textPath);
el.appendChild(path);
}
el.id = sprite.id;
sprite.el = Ext.get(el);
sprite.el.setStyle('zIndex', -me.zIndexShift);
me.el.appendChild(el);
if (type !== 'image') {
skew = me.createNode("skew");
skew.on = true;
el.appendChild(skew);
sprite.skew = skew;
}
sprite.matrix = new Ext.draw.Matrix();
sprite.bbox = {
plain: null,
transform: null
};
this.applyAttrs(sprite);
this.applyTransformations(sprite);
sprite.fireEvent("render", sprite);
return sprite.el;
},
getBBoxText: function (sprite) {
var vml = sprite.vml;
return {
x: vml.X + (vml.bbx || 0) - vml.W / 2,
y: vml.Y - vml.H / 2,
width: vml.W,
height: vml.H
};
},
applyAttrs: function (sprite) {
var me = this,
vml = sprite.vml,
group = sprite.group,
spriteAttr = sprite.attr,
el = sprite.el,
dom = el.dom,
style, name, groups, i, ln, scrubbedAttrs, font, key,
cx, cy, rx, ry;
if (group) {
groups = [].concat(group);
ln = groups.length;
for (i = 0; i < ln; i++) {
group = groups[i];
me.getGroup(group).add(sprite);
}
delete sprite.group;
}
scrubbedAttrs = me.scrubAttrs(sprite) || {};
if (sprite.zIndexDirty) {
me.setZIndex(sprite);
}
// Apply minimum default attributes
Ext.applyIf(scrubbedAttrs, me.minDefaults[sprite.type]);
if (sprite.type == 'image') {
Ext.apply(sprite.attr, {
x: scrubbedAttrs.x,
y: scrubbedAttrs.y,
width: scrubbedAttrs.width,
height: scrubbedAttrs.height
});
el.setStyle({
width: scrubbedAttrs.width + 'px',
height: scrubbedAttrs.height + 'px'
});
dom.src = scrubbedAttrs.src;
}
if (dom.href) {
dom.href = scrubbedAttrs.href;
}
if (dom.title) {
dom.title = scrubbedAttrs.title;
}
if (dom.target) {
dom.target = scrubbedAttrs.target;
}
if (dom.cursor) {
dom.cursor = scrubbedAttrs.cursor;
}
// Change visibility
if (sprite.dirtyHidden) {
(scrubbedAttrs.hidden) ? me.hidePrim(sprite) : me.showPrim(sprite);
sprite.dirtyHidden = false;
}
// Update path
if (sprite.dirtyPath) {
if (sprite.type == "circle" || sprite.type == "ellipse") {
cx = scrubbedAttrs.x;
cy = scrubbedAttrs.y;
rx = scrubbedAttrs.rx || scrubbedAttrs.r || 0;
ry = scrubbedAttrs.ry || scrubbedAttrs.r || 0;
dom.path = Ext.String.format("ar{0},{1},{2},{3},{4},{1},{4},{1}",
Math.round((cx - rx) * me.zoom),
Math.round((cy - ry) * me.zoom),
Math.round((cx + rx) * me.zoom),
Math.round((cy + ry) * me.zoom),
Math.round(cx * me.zoom));
sprite.dirtyPath = false;
}
else if (sprite.type !== "text" && sprite.type !== 'image') {
sprite.attr.path = scrubbedAttrs.path = me.setPaths(sprite, scrubbedAttrs) || scrubbedAttrs.path;
dom.path = me.path2vml(scrubbedAttrs.path);
sprite.dirtyPath = false;
}
}
// Apply clipping
if ("clip-rect" in scrubbedAttrs) {
me.setClip(sprite, scrubbedAttrs);
}
// Handle text (special handling required)
if (sprite.type == "text") {
me.setTextAttributes(sprite, scrubbedAttrs);
}
// Handle fill and opacity
if (scrubbedAttrs.opacity || scrubbedAttrs['stroke-opacity'] || scrubbedAttrs.fill) {
me.setFill(sprite, scrubbedAttrs);
}
// Handle stroke (all fills require a stroke element)
if (scrubbedAttrs.stroke || scrubbedAttrs['stroke-opacity'] || scrubbedAttrs.fill) {
me.setStroke(sprite, scrubbedAttrs);
}
//set styles
style = spriteAttr.style;
if (style) {
el.setStyle(style);
}
sprite.dirty = false;
},
setZIndex: function (sprite) {
var me = this,
zIndex = sprite.attr.zIndex,
shift = me.zIndexShift,
items, iLen, item, i;
if (zIndex < shift) {
// This means bad thing happened.
// The algorithm below will guarantee O(n) time.
items = me.items.items;
iLen = items.length;
for (i = 0; i < iLen; i++) {
if ((zIndex = items[i].attr.zIndex) && zIndex < shift) { // zIndex is no longer useful this case
shift = zIndex;
}
}
me.zIndexShift = shift;
for (i = 0; i < iLen; i++) {
item = items[i];
if (item.el) {
item.el.setStyle('zIndex', item.attr.zIndex - shift);
}
item.zIndexDirty = false;
}
} else if (sprite.el) {
sprite.el.setStyle('zIndex', zIndex - shift);
sprite.zIndexDirty = false;
}
},
// Normalize all virtualized types into paths.
setPaths: function (sprite, params) {
var spriteAttr = sprite.attr, thickness = sprite.attr['stroke-width'] || 1;
// Clear bbox cache
sprite.bbox.plain = null;
sprite.bbox.transform = null;
if (sprite.type == 'circle') {
spriteAttr.rx = spriteAttr.ry = params.r;
return Ext.draw.Draw.ellipsePath(sprite);
}
else if (sprite.type == 'ellipse') {
spriteAttr.rx = params.rx;
spriteAttr.ry = params.ry;
return Ext.draw.Draw.ellipsePath(sprite);
}
else if (sprite.type == 'rect') {
spriteAttr.rx = spriteAttr.ry = params.r;
return Ext.draw.Draw.rectPath(sprite);
}
else if (sprite.type == 'path' && spriteAttr.path) {
return Ext.draw.Draw.pathToAbsolute(spriteAttr.path);
}
return false;
},
setFill: function (sprite, params) {
var me = this,
el = sprite.el.dom,
fillEl = el.fill,
newfill = false,
opacity, gradient, fillUrl, rotation, angle;
if (!fillEl) {
// NOT an expando (but it sure looks like one)...
fillEl = el.fill = me.createNode("fill");
newfill = true;
}
if (Ext.isArray(params.fill)) {
params.fill = params.fill[0];
}
if (params.fill == "none") {
fillEl.on = false;
}
else {
if (typeof params.opacity == "number") {
fillEl.opacity = params.opacity;
}
if (typeof params["fill-opacity"] == "number") {
fillEl.opacity = params["fill-opacity"];
}
fillEl.on = true;
if (typeof params.fill == "string") {
fillUrl = params.fill.match(me.fillUrlRe);
if (fillUrl) {
fillUrl = fillUrl[1];
// If the URL matches one of the registered gradients, render that gradient
if (fillUrl.charAt(0) == "#") {
gradient = me.gradientsColl.getByKey(fillUrl.substring(1));
}
if (gradient) {
// VML angle is offset and inverted from standard, and must be adjusted to match rotation transform
rotation = params.rotation;
angle = -(gradient.angle + 270 + (rotation ? rotation.degrees : 0)) % 360;
// IE will flip the angle at 0 degrees...
if (angle === 0) {
angle = 180;
}
fillEl.angle = angle;
fillEl.type = "gradient";
fillEl.method = "sigma";
if (fillEl.colors) {
fillEl.colors.value = gradient.colors;
} else {
fillEl.colors = gradient.colors;
}
}
// Otherwise treat it as an image
else {
fillEl.src = fillUrl;
fillEl.type = "tile";
}
}
else {
fillEl.color = Ext.draw.Color.toHex(params.fill);
fillEl.src = "";
fillEl.type = "solid";
}
}
}
if (newfill) {
el.appendChild(fillEl);
}
},
setStroke: function (sprite, params) {
var me = this,
el = sprite.el.dom,
strokeEl = sprite.strokeEl,
newStroke = false,
width, opacity;
if (!strokeEl) {
strokeEl = sprite.strokeEl = me.createNode("stroke");
newStroke = true;
}
if (Ext.isArray(params.stroke)) {
params.stroke = params.stroke[0];
}
if (!params.stroke || params.stroke == "none" || params.stroke == 0 || params["stroke-width"] == 0) {
strokeEl.on = false;
}
else {
strokeEl.on = true;
if (params.stroke && !params.stroke.match(me.fillUrlRe)) {
// VML does NOT support a gradient stroke :(
strokeEl.color = Ext.draw.Color.toHex(params.stroke);
}
strokeEl.dashstyle = params["stroke-dasharray"] ? "dash" : "solid";
strokeEl.joinstyle = params["stroke-linejoin"];
strokeEl.endcap = params["stroke-linecap"] || "round";
strokeEl.miterlimit = params["stroke-miterlimit"] || 8;
width = parseFloat(params["stroke-width"] || 1) * 0.75;
opacity = params["stroke-opacity"] || 1;
// VML Does not support stroke widths under 1, so we're going to fiddle with stroke-opacity instead.
if (Ext.isNumber(width) && width < 1) {
strokeEl.weight = 1;
strokeEl.opacity = opacity * width;
}
else {
strokeEl.weight = width;
strokeEl.opacity = opacity;
}
}
if (newStroke) {
el.appendChild(strokeEl);
}
},
setClip: function (sprite, params) {
var me = this,
el = sprite.el,
clipEl = sprite.clipEl,
rect = String(params["clip-rect"]).split(me.separatorRe);
if (!clipEl) {
clipEl = sprite.clipEl = me.el.insertFirst(Ext.getDoc().dom.createElement("div"));
clipEl.addCls(Ext.baseCSSPrefix + 'vml-sprite');
}
if (rect.length == 4) {
rect[2] = +rect[2] + (+rect[0]);
rect[3] = +rect[3] + (+rect[1]);
clipEl.setStyle("clip", Ext.String.format("rect({1}px {2}px {3}px {0}px)", rect[0], rect[1], rect[2], rect[3]));
clipEl.setSize(me.el.width, me.el.height);
}
else {
clipEl.setStyle("clip", "");
}
},
setTextAttributes: function (sprite, params) {
var me = this,
vml = sprite.vml,
textStyle = vml.textpath.style,
spanCacheStyle = me.span.style,
zoom = me.zoom,
round = Math.round,
fontObj = {
fontSize: "font-size",
fontWeight: "font-weight",
fontStyle: "font-style"
},
fontProp,
paramProp;
if (sprite.dirtyFont) {
if (params.font) {
textStyle.font = spanCacheStyle.font = params.font;
}
if (params["font-family"]) {
textStyle.fontFamily = '"' + params["font-family"].split(",")[0].replace(me.fontFamilyRe, "") + '"';
spanCacheStyle.fontFamily = params["font-family"];
}
for (fontProp in fontObj) {
paramProp = params[fontObj[fontProp]];
if (paramProp) {
textStyle[fontProp] = spanCacheStyle[fontProp] = paramProp;
}
}
me.setText(sprite, params.text);
if (vml.textpath.string) {
me.span.innerHTML = String(vml.textpath.string).replace(/</g, "<").replace(/&/g, "&").replace(/\n/g, "<br/>");
}
vml.W = me.span.offsetWidth;
vml.H = me.span.offsetHeight + 2; // TODO handle baseline differences and offset in VML Textpath
// text-anchor emulation
if (params["text-anchor"] == "middle") {
textStyle["v-text-align"] = "center";
}
else if (params["text-anchor"] == "end") {
textStyle["v-text-align"] = "right";
vml.bbx = -Math.round(vml.W / 2);
}
else {
textStyle["v-text-align"] = "left";
vml.bbx = Math.round(vml.W / 2);
}
}
vml.X = params.x;
vml.Y = params.y;
vml.path.v = Ext.String.format("m{0},{1}l{2},{1}", Math.round(vml.X * zoom), Math.round(vml.Y * zoom), Math.round(vml.X * zoom) + 1);
// Clear bbox cache
sprite.bbox.plain = null;
sprite.bbox.transform = null;
sprite.dirtyFont = false;
},
setText: function (sprite, text) {
sprite.vml.textpath.string = Ext.htmlDecode(text);
},
hide: function () {
this.el.hide();
},
show: function () {
this.el.show();
},
hidePrim: function (sprite) {
sprite.el.addCls(Ext.baseCSSPrefix + 'hide-visibility');
},
showPrim: function (sprite) {
sprite.el.removeCls(Ext.baseCSSPrefix + 'hide-visibility');
},
setSize: function (width, height) {
var me = this;
width = width || me.width;
height = height || me.height;
me.width = width;
me.height = height;
if (me.el) {
// Size outer div
if (width != undefined) {
me.el.setWidth(width);
}
if (height != undefined) {
me.el.setHeight(height);
}
}
me.callParent(arguments);
},
/**
* @private Using the current viewBox property and the surface's width and height, calculate the
* appropriate viewBoxShift that will be applied as a persistent transform to all sprites.
*/
applyViewBox: function () {
var me = this,
viewBox = me.viewBox,
width = me.width,
height = me.height,
items,
iLen,
i;
me.callParent();
if (viewBox && (width || height)) {
items = me.items.items;
iLen = items.length;
for (i = 0; i < iLen; i++) {
me.applyTransformations(items[i]);
}
}
},
onAdd: function (item) {
this.callParent(arguments);
if (this.el) {
this.renderItem(item);
}
},
onRemove: function (sprite) {
if (sprite.el) {
sprite.el.remove();
delete sprite.el;
}
this.callParent(arguments);
},
render: function (container) {
var me = this,
doc = Ext.getDoc().dom,
el;
// VML Node factory method (createNode)
if (!me.createNode) {
try {
if (!doc.namespaces.rvml) {
doc.namespaces.add("rvml", "urn:schemas-microsoft-com:vml");
}
me.createNode = function (tagName) {
return doc.createElement("<rvml:" + tagName + ' class="rvml">');
};
} catch (e) {
me.createNode = function (tagName) {
return doc.createElement("<" + tagName + ' xmlns="urn:schemas-microsoft.com:vml" class="rvml">');
};
}
}
if (!me.el) {
el = doc.createElement("div");
me.el = Ext.get(el);
me.el.addCls(me.baseVmlCls);
// Measuring span (offscrren)
me.span = doc.createElement("span");
Ext.get(me.span).addCls(me.measureSpanCls);
el.appendChild(me.span);
me.el.setSize(me.width || 0, me.height || 0);
container.appendChild(el);
me.el.on({
scope: me,
mouseup: me.onMouseUp,
mousedown: me.onMouseDown,
mouseover: me.onMouseOver,
mouseout: me.onMouseOut,
mousemove: me.onMouseMove,
mouseenter: me.onMouseEnter,
mouseleave: me.onMouseLeave,
click: me.onClick,
dblclick: me.onDblClick
});
}
me.renderAll();
},
renderAll: function () {
this.items.each(this.renderItem, this);
},
redraw: function (sprite) {
sprite.dirty = true;
this.renderItem(sprite);
},
renderItem: function (sprite) {
// Does the surface element exist?
if (!this.el) {
return;
}
// Create sprite element if necessary
if (!sprite.el) {
this.createSpriteElement(sprite);
}
if (sprite.dirty) {
this.applyAttrs(sprite);
if (sprite.dirtyTransform) {
this.applyTransformations(sprite);
}
}
},
rotationCompensation: function (deg, dx, dy) {
var matrix = new Ext.draw.Matrix();
matrix.rotate(-deg, 0.5, 0.5);
return {
x: matrix.x(dx, dy),
y: matrix.y(dx, dy)
};
},
transform: function (sprite, matrixOnly) {
var me = this,
bbox = me.getBBox(sprite, true),
cx = bbox.x + bbox.width * 0.5,
cy = bbox.y + bbox.height * 0.5,
matrix = new Ext.draw.Matrix(),
transforms = sprite.transformations,
transformsLength = transforms.length,
i = 0,
deltaDegrees = 0,
deltaScaleX = 1,
deltaScaleY = 1,
flip = "",
el = sprite.el,
dom = el.dom,
domStyle = dom.style,
zoom = me.zoom,
skew = sprite.skew,
shift = me.viewBoxShift,
deltaX, deltaY, transform, type, compensate, y, fill, newAngle, zoomScaleX, zoomScaleY, newOrigin, offset;
for (; i < transformsLength; i++) {
transform = transforms[i];
type = transform.type;
if (type == "translate") {
matrix.translate(transform.x, transform.y);
}
else if (type == "rotate") {
matrix.rotate(transform.degrees, transform.x, transform.y);
deltaDegrees += transform.degrees;
}
else if (type == "scale") {
matrix.scale(transform.x, transform.y, transform.centerX, transform.centerY);
deltaScaleX *= transform.x;
deltaScaleY *= transform.y;
}
}
sprite.matrix = matrix.clone();
if (matrixOnly) {
return;
}
if (shift) {
matrix.prepend(shift.scale, 0, 0, shift.scale, shift.dx * shift.scale, shift.dy * shift.scale);
}
// Hide element while we transform
if (sprite.type != "image" && skew) {
skew.origin = "0,0";
// matrix transform via VML skew
skew.matrix = matrix.toString();
// skew.offset = '32767,1' OK
// skew.offset = '32768,1' Crash
// M$, R U kidding??
offset = matrix.offset();
if (offset[0] > 32767) {
offset[0] = 32767;
} else if (offset[0] < -32768) {
offset[0] = -32768;
}
if (offset[1] > 32767) {
offset[1] = 32767;
} else if (offset[1] < -32768) {
offset[1] = -32768;
}
skew.offset = offset;
}
else {
domStyle.filter = matrix.toFilter();
domStyle.left = Math.min(
matrix.x(bbox.x, bbox.y),
matrix.x(bbox.x + bbox.width, bbox.y),
matrix.x(bbox.x, bbox.y + bbox.height),
matrix.x(bbox.x + bbox.width, bbox.y + bbox.height)) + 'px';
domStyle.top = Math.min(
matrix.y(bbox.x, bbox.y),
matrix.y(bbox.x + bbox.width, bbox.y),
matrix.y(bbox.x, bbox.y + bbox.height),
matrix.y(bbox.x + bbox.width, bbox.y + bbox.height)) + 'px';
}
},
createItem: function (config) {
return Ext.create('Ext.draw.Sprite', config);
},
getRegion: function () {
return this.el.getRegion();
},
addCls: function (sprite, className) {
if (sprite && sprite.el) {
sprite.el.addCls(className);
}
},
removeCls: function (sprite, className) {
if (sprite && sprite.el) {
sprite.el.removeCls(className);
}
},
/**
* Adds a definition to this Surface for a linear gradient. We convert the gradient definition
* to its corresponding VML attributes and store it for later use by individual sprites.
* @param {Object} gradient
*/
addGradient: function (gradient) {
var gradients = this.gradientsColl || (this.gradientsColl = Ext.create('Ext.util.MixedCollection')),
colors = [],
stops = Ext.create('Ext.util.MixedCollection'),
keys,
items,
iLen,
key,
item,
i;
// Build colors string
stops.addAll(gradient.stops);
stops.sortByKey("ASC", function (a, b) {
a = parseInt(a, 10);
b = parseInt(b, 10);
return a > b ? 1 : (a < b ? -1 : 0);
});
keys = stops.keys;
items = stops.items;
iLen = keys.length;
for (i = 0; i < iLen; i++) {
key = keys[i];
item = items[i];
colors.push(key + '% ' + item.color);
}
gradients.add(gradient.id, {
colors: colors.join(","),
angle: gradient.angle
});
},
destroy: function () {
var me = this;
me.callParent(arguments);
if (me.el) {
me.el.remove();
}
delete me.el;
}
});
|