]>
Commit | Line | Data |
---|---|---|
6527f429 DM |
1 | /**\r |
2 | * @class Ext.draw.engine.Svg\r | |
3 | * @extends Ext.draw.Surface\r | |
4 | *\r | |
5 | * SVG engine.\r | |
6 | */\r | |
7 | Ext.define('Ext.draw.engine.Svg', {\r | |
8 | extend: 'Ext.draw.Surface',\r | |
9 | requires: ['Ext.draw.engine.SvgContext'],\r | |
10 | \r | |
11 | statics: {\r | |
12 | BBoxTextCache: {}\r | |
13 | },\r | |
14 | \r | |
15 | config: {\r | |
16 | /**\r | |
17 | * Nothing needs to be done in high precision mode.\r | |
18 | */\r | |
19 | highPrecision: false\r | |
20 | },\r | |
21 | \r | |
22 | getElementConfig: function () {\r | |
23 | //TODO:ps In the Ext world, use renderTpl to create the children\r | |
24 | return {\r | |
25 | reference: 'element',\r | |
26 | style: {\r | |
27 | position: 'absolute'\r | |
28 | },\r | |
29 | children: [\r | |
30 | {\r | |
31 | reference: 'innerElement',\r | |
32 | style: {\r | |
33 | width: '100%',\r | |
34 | height: '100%',\r | |
35 | position: 'relative'\r | |
36 | },\r | |
37 | children: [\r | |
38 | {\r | |
39 | tag: 'svg',\r | |
40 | reference: 'svgElement',\r | |
41 | namespace: "http://www.w3.org/2000/svg",\r | |
42 | width: '100%',\r | |
43 | height: '100%',\r | |
44 | version: 1.1\r | |
45 | }\r | |
46 | ]\r | |
47 | }\r | |
48 | ]\r | |
49 | };\r | |
50 | },\r | |
51 | \r | |
52 | constructor: function (config) {\r | |
53 | var me = this;\r | |
54 | me.callParent([config]);\r | |
55 | me.mainGroup = me.createSvgNode("g");\r | |
56 | me.defElement = me.createSvgNode("defs");\r | |
57 | // me.svgElement is assigned in element creation of Ext.Component.\r | |
58 | me.svgElement.appendChild(me.mainGroup);\r | |
59 | me.svgElement.appendChild(me.defElement);\r | |
60 | me.ctx = new Ext.draw.engine.SvgContext(me);\r | |
61 | },\r | |
62 | \r | |
63 | /**\r | |
64 | * Creates a DOM element under the SVG namespace of the given type.\r | |
65 | * @param {String} type The type of the SVG DOM element.\r | |
66 | * @return {*} The created element.\r | |
67 | */\r | |
68 | createSvgNode: function (type) {\r | |
69 | var node = document.createElementNS("http://www.w3.org/2000/svg", type);\r | |
70 | return Ext.get(node);\r | |
71 | },\r | |
72 | \r | |
73 | /**\r | |
74 | * @private\r | |
75 | * Returns the SVG DOM element at the given position. If it does not already exist or is a different element tag\r | |
76 | * it will be created and inserted into the DOM.\r | |
77 | * @param {Ext.dom.Element} group The parent DOM element.\r | |
78 | * @param {String} tag The SVG element tag.\r | |
79 | * @param {Number} position The position of the element in the DOM.\r | |
80 | * @return {Ext.dom.Element} The SVG element.\r | |
81 | */\r | |
82 | getSvgElement: function (group, tag, position) {\r | |
83 | var element;\r | |
84 | if (group.dom.childNodes.length > position) {\r | |
85 | element = group.dom.childNodes[position];\r | |
86 | if (element.tagName === tag) {\r | |
87 | return Ext.get(element);\r | |
88 | } else {\r | |
89 | Ext.destroy(element);\r | |
90 | }\r | |
91 | }\r | |
92 | \r | |
93 | element = Ext.get(this.createSvgNode(tag));\r | |
94 | if (position === 0) {\r | |
95 | group.insertFirst(element);\r | |
96 | } else {\r | |
97 | element.insertAfter(Ext.fly(group.dom.childNodes[position - 1]));\r | |
98 | }\r | |
99 | element.cache = {};\r | |
100 | return element;\r | |
101 | },\r | |
102 | \r | |
103 | /**\r | |
104 | * @private\r | |
105 | * Applies attributes to the given element.\r | |
106 | * @param {Ext.dom.Element} element The DOM element to be applied.\r | |
107 | * @param {Object} attributes The attributes to apply to the element.\r | |
108 | */\r | |
109 | setElementAttributes: function (element, attributes) {\r | |
110 | var dom = element.dom,\r | |
111 | cache = element.cache,\r | |
112 | name, value;\r | |
113 | for (name in attributes) {\r | |
114 | value = attributes[name];\r | |
115 | if (cache[name] !== value) {\r | |
116 | cache[name] = value;\r | |
117 | dom.setAttribute(name, value);\r | |
118 | }\r | |
119 | }\r | |
120 | },\r | |
121 | \r | |
122 | /**\r | |
123 | * @private\r | |
124 | * Gets the next reference element under the SVG 'defs' tag.\r | |
125 | * @param {String} tagName The type of reference element.\r | |
126 | * @return {Ext.dom.Element} The reference element.\r | |
127 | */\r | |
128 | getNextDef: function (tagName) {\r | |
129 | return this.getSvgElement(this.defElement, tagName, this.defPosition++);\r | |
130 | },\r | |
131 | \r | |
132 | /**\r | |
133 | * @inheritdoc\r | |
134 | */\r | |
135 | clearTransform: function () {\r | |
136 | var me = this;\r | |
137 | me.mainGroup.set({transform: me.matrix.toSvg()});\r | |
138 | },\r | |
139 | \r | |
140 | /**\r | |
141 | * @inheritdoc\r | |
142 | */\r | |
143 | clear: function () {\r | |
144 | this.ctx.clear();\r | |
145 | this.defPosition = 0;\r | |
146 | },\r | |
147 | \r | |
148 | /**\r | |
149 | * @inheritdoc\r | |
150 | */\r | |
151 | renderSprite: function (sprite) {\r | |
152 | var me = this,\r | |
153 | rect = me.getRect(),\r | |
154 | ctx = me.ctx;\r | |
155 | \r | |
156 | if (sprite.attr.hidden || sprite.attr.globalAlpha === 0) {\r | |
157 | ctx.save();\r | |
158 | ctx.restore();\r | |
159 | return;\r | |
160 | }\r | |
161 | \r | |
162 | sprite.element = ctx.save();\r | |
163 | sprite.preRender(this);\r | |
164 | sprite.useAttributes(ctx, rect);\r | |
165 | if (false === sprite.render(this, ctx, [0, 0, rect[2], rect[3]])) {\r | |
166 | return false;\r | |
167 | }\r | |
168 | sprite.setDirty(false);\r | |
169 | ctx.restore();\r | |
170 | },\r | |
171 | \r | |
172 | flatten: function (size, surfaces) {\r | |
173 | var svg = '<?xml version="1.0" standalone="yes"?>',\r | |
174 | className = Ext.getClassName(this),\r | |
175 | surface, rect, i;\r | |
176 | \r | |
177 | svg += '<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg"' +\r | |
178 | ' width="' + size.width + '"' +\r | |
179 | ' height="' + size.height + '">';\r | |
180 | \r | |
181 | for (i = 0; i < surfaces.length; i++) {\r | |
182 | surface = surfaces[i];\r | |
183 | if (Ext.getClassName(surface) !== className) {\r | |
184 | continue;\r | |
185 | }\r | |
186 | rect = surface.getRect();\r | |
187 | svg += '<g transform="translate(' + rect[0] + ',' + rect[1] + ')">';\r | |
188 | svg += this.serializeNode(surface.svgElement.dom);\r | |
189 | svg += '</g>';\r | |
190 | }\r | |
191 | svg += '</svg>';\r | |
192 | return {\r | |
193 | data: 'data:image/svg+xml;utf8,' + encodeURIComponent(svg),\r | |
194 | type: 'svg'\r | |
195 | };\r | |
196 | },\r | |
197 | \r | |
198 | /**\r | |
199 | * @private\r | |
200 | * Serializes an SVG DOM element and its children recursively into a string.\r | |
201 | * @param {Object} node DOM element to serialize.\r | |
202 | * @return {String}\r | |
203 | */\r | |
204 | serializeNode: function (node) {\r | |
205 | var result = '',\r | |
206 | i, n, attr, child;\r | |
207 | if (node.nodeType === document.TEXT_NODE) {\r | |
208 | return node.nodeValue;\r | |
209 | }\r | |
210 | result += '<' + node.nodeName;\r | |
211 | if (node.attributes.length) {\r | |
212 | for (i = 0, n = node.attributes.length; i < n; i++) {\r | |
213 | attr = node.attributes[i];\r | |
214 | result += ' ' + attr.name + '="' + attr.value + '"';\r | |
215 | }\r | |
216 | }\r | |
217 | result += '>';\r | |
218 | if (node.childNodes && node.childNodes.length) {\r | |
219 | for (i = 0, n = node.childNodes.length; i < n; i++) {\r | |
220 | child = node.childNodes[i];\r | |
221 | result += this.serializeNode(child);\r | |
222 | }\r | |
223 | }\r | |
224 | result += '</' + node.nodeName + '>';\r | |
225 | return result;\r | |
226 | },\r | |
227 | \r | |
228 | /**\r | |
229 | * Destroys the Canvas element and prepares it for Garbage Collection.\r | |
230 | */\r | |
231 | destroy: function () {\r | |
232 | var me = this;\r | |
233 | me.ctx.destroy();\r | |
234 | me.mainGroup.destroy();\r | |
235 | delete me.mainGroup;\r | |
236 | delete me.ctx;\r | |
237 | me.callParent();\r | |
238 | },\r | |
239 | \r | |
240 | remove: function (sprite, destroySprite) {\r | |
241 | if (sprite && sprite.element) {\r | |
242 | // If sprite has an associated SVG element, remove it from the surface.\r | |
243 | if (this.ctx) {\r | |
244 | this.ctx.removeElement(sprite.element);\r | |
245 | } else {\r | |
246 | sprite.element.destroy();\r | |
247 | }\r | |
248 | sprite.element = null;\r | |
249 | }\r | |
250 | this.callParent(arguments);\r | |
251 | }\r | |
252 | });\r |