| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754 | <!DOCTYPE html><html><head>  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  <title>The source code</title>  <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />  <script type="text/javascript" src="../resources/prettify/prettify.js"></script>  <style type="text/css">    .highlight { display: block; background-color: #ddd; }  </style>  <script type="text/javascript">    function highlight() {      document.getElementById(location.hash.replace(/#/, "")).className = "highlight";    }  </script></head><body onload="prettyPrint(); highlight();">  <pre class="prettyprint lang-js"><span id='Ext-draw-engine-Svg'>/**</span> * Provides specific methods to draw with SVG. */Ext.define('Ext.draw.engine.Svg', {    /* Begin Definitions */    extend: 'Ext.draw.Surface',    requires: ['Ext.draw.Draw', 'Ext.draw.Sprite', 'Ext.draw.Matrix', 'Ext.Element'],    /* End Definitions */    engine: 'Svg',    trimRe: /^\s+|\s+$/g,    spacesRe: /\s+/,    xlink: "http:/" + "/www.w3.org/1999/xlink",    translateAttrs: {        radius: "r",        radiusX: "rx",        radiusY: "ry",        path: "d",        lineWidth: "stroke-width",        fillOpacity: "fill-opacity",        strokeOpacity: "stroke-opacity",        strokeLinejoin: "stroke-linejoin"    },    parsers: {},    minDefaults: {        circle: {            cx: 0,            cy: 0,            r: 0,            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-family": null,            "font-size": null,            "font-weight": null,            "font-style": null,            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        }    },    createSvgElement: function(type, attrs) {        var el = this.domRef.createElementNS("http:/" + "/www.w3.org/2000/svg", type),            key;        if (attrs) {            for (key in attrs) {                el.setAttribute(key, String(attrs[key]));            }        }        return el;    },    createSpriteElement: function(sprite) {        // Create svg element and append to the DOM.        var el = this.createSvgElement(sprite.type);        el.id = sprite.id;        if (el.style) {            el.style.webkitTapHighlightColor = "rgba(0,0,0,0)";        }        sprite.el = Ext.get(el);        this.applyZIndex(sprite); //performs the insertion        sprite.matrix = new Ext.draw.Matrix();        sprite.bbox = {            plain: 0,            transform: 0        };        this.applyAttrs(sprite);        this.applyTransformations(sprite);        sprite.fireEvent("render", sprite);        return el;    },        getBBoxText: function (sprite) {        var bbox = {},            bb, height, width, i, ln, el;        if (sprite && sprite.el) {            el = sprite.el.dom;            try {                bbox = el.getBBox();                return bbox;            } catch(e) {                // Firefox 3.0.x plays badly here            }            bbox = {x: bbox.x, y: Infinity, width: 0, height: 0};            ln = el.getNumberOfChars();            for (i = 0; i < ln; i++) {                bb = el.getExtentOfChar(i);                bbox.y = Math.min(bb.y, bbox.y);                height = bb.y + bb.height - bbox.y;                bbox.height = Math.max(bbox.height, height);                width = bb.x + bb.width - bbox.x;                bbox.width = Math.max(bbox.width, width);            }            return bbox;        }    },    hide: function() {        Ext.get(this.el).hide();    },    show: function() {        Ext.get(this.el).show();    },    hidePrim: function(sprite) {        this.addCls(sprite, Ext.baseCSSPrefix + 'hide-visibility');    },    showPrim: function(sprite) {        this.removeCls(sprite, Ext.baseCSSPrefix + 'hide-visibility');    },    getDefs: function() {        return this._defs || (this._defs = this.createSvgElement("defs"));    },    transform: function(sprite, matrixOnly) {        var me = this,            matrix = new Ext.draw.Matrix(),            transforms = sprite.transformations,            transformsLength = transforms.length,            i = 0,            transform, type;                    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);            }            else if (type == "scale") {                matrix.scale(transform.x, transform.y, transform.centerX, transform.centerY);            }        }        sprite.matrix = matrix;        if (!matrixOnly) {            sprite.el.set({transform: matrix.toSvg()});        }    },    setSize: function(width, height) {        var me = this,            el = me.el;                width = +width || me.width;        height = +height || me.height;        me.width = width;        me.height = height;        el.setSize(width, height);        el.set({            width: width,            height: height        });        me.callParent([width, height]);    },<span id='Ext-draw-engine-Svg-method-getRegion'>    /**</span>     * Get the region for the surface's canvas area     * @returns {Ext.util.Region}     */    getRegion: function() {        // Mozilla requires using the background rect because the svg element returns an        // incorrect region. Webkit gives no region for the rect and must use the svg element.        var svgXY = this.el.getXY(),            rectXY = this.bgRect.getXY(),            max = Math.max,            x = max(svgXY[0], rectXY[0]),            y = max(svgXY[1], rectXY[1]);        return {            left: x,            top: y,            right: x + this.width,            bottom: y + this.height        };    },    onRemove: function(sprite) {        if (sprite.el) {            sprite.el.destroy();            delete sprite.el;        }        this.callParent(arguments);    },        setViewBox: function(x, y, width, height) {        if (isFinite(x) && isFinite(y) && isFinite(width) && isFinite(height)) {            this.callParent(arguments);            this.el.dom.setAttribute("viewBox", [x, y, width, height].join(" "));        }    },    render: function (container) {        var me = this,            width,            height,            el,            defs,            bgRect,            webkitRect;        if (!me.el) {            width = me.width || 0;            height = me.height || 0;            el = me.createSvgElement('svg', {                xmlns: "http:/" + "/www.w3.org/2000/svg",                version: 1.1,                width: width,                height: height            });            defs = me.getDefs();            // Create a rect that is always the same size as the svg root; this serves 2 purposes:            // (1) It allows mouse events to be fired over empty areas in Webkit, and (2) we can            // use it rather than the svg element for retrieving the correct client rect of the            // surface in Mozilla (see https://bugzilla.mozilla.org/show_bug.cgi?id=530985)            bgRect = me.createSvgElement("rect", {                width: "100%",                height: "100%",                fill: "#000",                stroke: "none",                opacity: 0            });                        if (Ext.isSafari3) {                // Rect that we will show/hide to fix old WebKit bug with rendering issues.                webkitRect = me.createSvgElement("rect", {                    x: -10,                    y: -10,                    width: "110%",                    height: "110%",                    fill: "none",                    stroke: "#000"                });            }            el.appendChild(defs);            if (Ext.isSafari3) {                el.appendChild(webkitRect);            }            el.appendChild(bgRect);            container.appendChild(el);            me.el = Ext.get(el);            me.bgRect = Ext.get(bgRect);            if (Ext.isSafari3) {                me.webkitRect = Ext.get(webkitRect);                me.webkitRect.hide();            }            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();    },    // private    onMouseEnter: function(e) {        if (this.el.parent().getRegion().contains(e.getPoint())) {            this.fireEvent('mouseenter', e);        }    },    // private    onMouseLeave: function(e) {        if (!this.el.parent().getRegion().contains(e.getPoint())) {            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);        // We wrap text types in a tspan, sprite is the parent.        if (target.nodeName == "tspan" && target.parentNode) {            target = target.parentNode;        }        sprite = this.items.get(target.id);        if (sprite) {            sprite.fireEvent(name, sprite, e);        }    },    /* @private - Wrap SVG text inside a tspan to allow for line wrapping.  In addition this normallizes     * the baseline for text the vertical middle of the text to be the same as VML.     */    tuneText: function (sprite, attrs) {        var el = sprite.el.dom,            tspans = [],            height, tspan, text, i, ln, texts, factor, x;        if (attrs.hasOwnProperty("text")) {            //only create new tspans for text lines if the text has been             //updated or if it's the first time we're setting the text            //into the sprite.            //get the actual rendered text.            text = sprite.tspans && Ext.Array.map(sprite.tspans, function(t) { return t.textContent; }).join('');            if (!sprite.tspans || attrs.text != text) {                tspans = this.setText(sprite, attrs.text);                sprite.tspans = tspans;            //for all other cases reuse the tspans previously created.            } else {                tspans = sprite.tspans || [];            }        }        // Normalize baseline via a DY shift of first tspan. Shift other rows by height * line height (1.2)        if (tspans.length) {            height = this.getBBoxText(sprite).height;            x = sprite.el.dom.getAttribute("x");            for (i = 0, ln = tspans.length; i < ln; i++) {                // The text baseline for FireFox 3.0 and 3.5 is different than other SVG implementations                // so we are going to normalize that here                factor = (Ext.isFF3_0 || Ext.isFF3_5) ? 2 : 4;                tspans[i].setAttribute("x", x);                tspans[i].setAttribute("dy", i ? height * 1.2 : height / factor);            }            sprite.dirty = true;        }    },    setText: function(sprite, textString) {         var me = this,             el = sprite.el.dom,             tspans = [],             height, tspan, text, i, ln, texts;                while (el.firstChild) {            el.removeChild(el.firstChild);        }        // Wrap each row into tspan to emulate rows        texts = String(textString).split("\n");        for (i = 0, ln = texts.length; i < ln; i++) {            text = texts[i];            if (text) {                tspan = me.createSvgElement("tspan");                tspan.appendChild(document.createTextNode(Ext.htmlDecode(text)));                el.appendChild(tspan);                tspans[i] = tspan;            }        }        return tspans;    },    renderAll: function() {        this.items.each(this.renderItem, this);    },    renderItem: function (sprite) {        if (!this.el) {            return;        }        if (!sprite.el) {            this.createSpriteElement(sprite);        }        if (sprite.zIndexDirty) {            this.applyZIndex(sprite);        }        if (sprite.dirty) {            this.applyAttrs(sprite);            if (sprite.dirtyTransform) {                this.applyTransformations(sprite);            }        }    },    redraw: function(sprite) {        sprite.dirty = sprite.zIndexDirty = true;        this.renderItem(sprite);    },    applyAttrs: function (sprite) {        var me = this,            el = sprite.el,            group = sprite.group,            sattr = sprite.attr,            parsers = me.parsers,            //Safari does not handle linear gradients correctly in quirksmode            //ref: https://bugs.webkit.org/show_bug.cgi?id=41952            //ref: EXTJSIV-1472            gradientsMap = me.gradientsMap || {},            safariFix = Ext.isSafari && !Ext.isStrict,            groups, i, ln, attrs, font, key, style, name, rect;        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;        }        attrs = me.scrubAttrs(sprite) || {};        // if (sprite.dirtyPath) {            sprite.bbox.plain = 0;            sprite.bbox.transform = 0;            if (sprite.type == "circle" || sprite.type == "ellipse") {                attrs.cx = attrs.cx || attrs.x;                attrs.cy = attrs.cy || attrs.y;            }            else if (sprite.type == "rect") {                attrs.rx = attrs.ry = attrs.r;            }            else if (sprite.type == "path" && attrs.d) {                attrs.d = Ext.draw.Draw.pathToString(Ext.draw.Draw.pathToAbsolute(attrs.d));            }            sprite.dirtyPath = false;        // }        // else {        //     delete attrs.d;        // }        if (attrs['clip-rect']) {            me.setClip(sprite, attrs);            delete attrs['clip-rect'];        }        if (sprite.type == 'text' && attrs.font && sprite.dirtyFont) {            el.set({ style: "font: " + attrs.font});        }        if (sprite.type == "image") {            el.dom.setAttributeNS(me.xlink, "href", attrs.src);        }        Ext.applyIf(attrs, me.minDefaults[sprite.type]);        if (sprite.dirtyHidden) {            (sattr.hidden) ? me.hidePrim(sprite) : me.showPrim(sprite);            sprite.dirtyHidden = false;        }        for (key in attrs) {            if (attrs.hasOwnProperty(key) && attrs[key] != null) {                //Safari does not handle linear gradients correctly in quirksmode                //ref: https://bugs.webkit.org/show_bug.cgi?id=41952                //ref: EXTJSIV-1472                //if we're Safari in QuirksMode and we're applying some color attribute and the value of that                //attribute is a reference to a gradient then assign a plain color to that value instead of the gradient.                if (safariFix && ('color|stroke|fill'.indexOf(key) > -1) && (attrs[key] in gradientsMap)) {                    attrs[key] = gradientsMap[attrs[key]];                }                //hidden is not a proper SVG attribute.                if (key == 'hidden' && sprite.type == 'text') {                    continue;                }                if (key in parsers) {                    el.dom.setAttribute(key, parsers[key](attrs[key], sprite, me));                } else {                    el.dom.setAttribute(key, attrs[key]);                }            }        }                if (sprite.type == 'text') {            me.tuneText(sprite, attrs);        }        sprite.dirtyFont = false;        //set styles        style = sattr.style;        if (style) {            el.setStyle(style);        }        sprite.dirty = false;        if (Ext.isSafari3) {            // Refreshing the view to fix bug EXTJSIV-1: rendering issue in old Safari 3            me.webkitRect.show();            setTimeout(function () {                me.webkitRect.hide();            });        }    },    setClip: function(sprite, params) {        var me = this,            rect = params["clip-rect"],            clipEl, clipPath;        if (rect) {            if (sprite.clip) {                sprite.clip.parentNode.parentNode.removeChild(sprite.clip.parentNode);            }            clipEl = me.createSvgElement('clipPath');            clipPath = me.createSvgElement('rect');            clipEl.id = Ext.id(null, 'ext-clip-');            clipPath.setAttribute("x", rect.x);            clipPath.setAttribute("y", rect.y);            clipPath.setAttribute("width", rect.width);            clipPath.setAttribute("height", rect.height);            clipEl.appendChild(clipPath);            me.getDefs().appendChild(clipEl);            sprite.el.dom.setAttribute("clip-path", "url(#" + clipEl.id + ")");            sprite.clip = clipPath;        }         // if (!attrs[key]) {        //     var clip = Ext.getDoc().dom.getElementById(sprite.el.getAttribute("clip-path").replace(/(^url\(#|\)$)/g, ""));        //     clip && clip.parentNode.removeChild(clip);        //     sprite.el.setAttribute("clip-path", "");        //     delete attrss.clip;        // }    },<span id='Ext-draw-engine-Svg-method-applyZIndex'>    /**</span>     * Insert or move a given sprite's element to the correct place in the DOM list for its zIndex     * @param {Ext.draw.Sprite} sprite     */    applyZIndex: function(sprite) {        var me = this,            items = me.items,            idx = items.indexOf(sprite),            el = sprite.el,            prevEl;        if (me.el.dom.childNodes[idx + 2] !== el.dom) { //shift by 2 to account for defs and bg rect            if (idx > 0) {                // Find the first previous sprite which has its DOM element created already                do {                    prevEl = items.getAt(--idx).el;                } while (!prevEl && idx > 0);            }            el.insertAfter(prevEl || me.bgRect);        }        sprite.zIndexDirty = false;    },    createItem: function (config) {        var sprite = new Ext.draw.Sprite(config);        sprite.surface = this;        return sprite;    },    addGradient: function(gradient) {        gradient = Ext.draw.Draw.parseGradient(gradient);        var me = this,            ln = gradient.stops.length,            vector = gradient.vector,            //Safari does not handle linear gradients correctly in quirksmode            //ref: https://bugs.webkit.org/show_bug.cgi?id=41952            //ref: EXTJSIV-1472            usePlain = Ext.isSafari && !Ext.isStrict,            gradientEl, stop, stopEl, i, gradientsMap;                    gradientsMap = me.gradientsMap || {};                if (!usePlain) {            if (gradient.type == "linear") {                gradientEl = me.createSvgElement("linearGradient");                gradientEl.setAttribute("x1", vector[0]);                gradientEl.setAttribute("y1", vector[1]);                gradientEl.setAttribute("x2", vector[2]);                gradientEl.setAttribute("y2", vector[3]);            }            else {                gradientEl = me.createSvgElement("radialGradient");                gradientEl.setAttribute("cx", gradient.centerX);                gradientEl.setAttribute("cy", gradient.centerY);                gradientEl.setAttribute("r", gradient.radius);                if (Ext.isNumber(gradient.focalX) && Ext.isNumber(gradient.focalY)) {                    gradientEl.setAttribute("fx", gradient.focalX);                    gradientEl.setAttribute("fy", gradient.focalY);                }            }            gradientEl.id = gradient.id;            me.getDefs().appendChild(gradientEl);            for (i = 0; i < ln; i++) {                stop = gradient.stops[i];                stopEl = me.createSvgElement("stop");                stopEl.setAttribute("offset", stop.offset + "%");                stopEl.setAttribute("stop-color", stop.color);                stopEl.setAttribute("stop-opacity",stop.opacity);                gradientEl.appendChild(stopEl);            }        } else {            gradientsMap['url(#' + gradient.id + ')'] = gradient.stops[0].color;        }        me.gradientsMap = gradientsMap;    },<span id='Ext-draw-engine-Svg-method-hasCls'>    /**</span>     * Checks if the specified CSS class exists on this element's DOM node.     * @param {Ext.draw.Sprite} sprite The sprite to look into.     * @param {String} className The CSS class to check for     * @return {Boolean} True if the class exists, else false     */    hasCls: function(sprite, className) {        return className && (' ' + (sprite.el.dom.getAttribute('class') || '') + ' ').indexOf(' ' + className + ' ') != -1;    },    addCls: function(sprite, className) {        var el = sprite.el,            i,            len,            v,            cls = [],            curCls =  el.getAttribute('class') || '';        // Separate case is for speed        if (!Ext.isArray(className)) {            if (typeof className == 'string' && !this.hasCls(sprite, className)) {                el.set({ 'class': curCls + ' ' + className });            }        }        else {            for (i = 0, len = className.length; i < len; i++) {                v = className[i];                if (typeof v == 'string' && (' ' + curCls + ' ').indexOf(' ' + v + ' ') == -1) {                    cls.push(v);                }            }            if (cls.length) {                el.set({ 'class': ' ' + cls.join(' ') });            }        }    },    removeCls: function(sprite, className) {        var me = this,            el = sprite.el,            curCls =  el.getAttribute('class') || '',            i, idx, len, cls, elClasses;        if (!Ext.isArray(className)){            className = [className];        }        if (curCls) {            elClasses = curCls.replace(me.trimRe, ' ').split(me.spacesRe);            for (i = 0, len = className.length; i < len; i++) {                cls = className[i];                if (typeof cls == 'string') {                    cls = cls.replace(me.trimRe, '');                    idx = Ext.Array.indexOf(elClasses, cls);                    if (idx != -1) {                        Ext.Array.erase(elClasses, idx, 1);                    }                }            }            el.set({ 'class': elClasses.join(' ') });        }    },    destroy: function() {        var me = this;                me.callParent();        if (me.el) {            me.el.remove();        }        if (me._defs) {            Ext.get(me._defs).destroy();        }        if (me.bgRect) {            Ext.get(me.bgRect).destroy();        }        if (me.webkitRect) {            Ext.get(me.webkitRect).destroy();        }        delete me.el;    }});</pre></body></html>
 |