UNPKG

11.8 kBJavaScriptView Raw
1import { createElement, SVGNS, XLINKNS, XMLNS } from '../svg/core.js';
2import { normalizeColor } from '../svg/helper.js';
3import * as util from '../core/util.js';
4import Path from '../graphic/Path.js';
5import ZRImage from '../graphic/Image.js';
6import TSpan from '../graphic/TSpan.js';
7import arrayDiff from '../core/arrayDiff.js';
8import GradientManager from './helper/GradientManager.js';
9import PatternManager from './helper/PatternManager.js';
10import ClippathManager, { hasClipPath } from './helper/ClippathManager.js';
11import ShadowManager from './helper/ShadowManager.js';
12import { path as svgPath, image as svgImage, text as svgText } from './graphic.js';
13import { getSize } from '../canvas/helper.js';
14function getSvgProxy(el) {
15 if (el instanceof Path) {
16 return svgPath;
17 }
18 else if (el instanceof ZRImage) {
19 return svgImage;
20 }
21 else if (el instanceof TSpan) {
22 return svgText;
23 }
24 else {
25 return svgPath;
26 }
27}
28function checkParentAvailable(parent, child) {
29 return child && parent && child.parentNode !== parent;
30}
31function insertAfter(parent, child, prevSibling) {
32 if (checkParentAvailable(parent, child) && prevSibling) {
33 var nextSibling = prevSibling.nextSibling;
34 nextSibling ? parent.insertBefore(child, nextSibling)
35 : parent.appendChild(child);
36 }
37}
38function prepend(parent, child) {
39 if (checkParentAvailable(parent, child)) {
40 var firstChild = parent.firstChild;
41 firstChild ? parent.insertBefore(child, firstChild)
42 : parent.appendChild(child);
43 }
44}
45function remove(parent, child) {
46 if (child && parent && child.parentNode === parent) {
47 parent.removeChild(child);
48 }
49}
50function removeFromMyParent(child) {
51 if (child && child.parentNode) {
52 child.parentNode.removeChild(child);
53 }
54}
55function getSvgElement(displayable) {
56 return displayable.__svgEl;
57}
58var SVGPainter = (function () {
59 function SVGPainter(root, storage, opts, zrId) {
60 this.type = 'svg';
61 this.refreshHover = createMethodNotSupport('refreshHover');
62 this.configLayer = createMethodNotSupport('configLayer');
63 this.root = root;
64 this.storage = storage;
65 this._opts = opts = util.extend({}, opts || {});
66 var svgDom = createElement('svg');
67 svgDom.setAttributeNS(XMLNS, 'xmlns', SVGNS);
68 svgDom.setAttributeNS(XMLNS, 'xmlns:xlink', XLINKNS);
69 svgDom.setAttribute('version', '1.1');
70 svgDom.setAttribute('baseProfile', 'full');
71 svgDom.style.cssText = 'user-select:none;position:absolute;left:0;top:0;';
72 var bgRoot = createElement('g');
73 svgDom.appendChild(bgRoot);
74 var svgRoot = createElement('g');
75 svgDom.appendChild(svgRoot);
76 this._gradientManager = new GradientManager(zrId, svgRoot);
77 this._patternManager = new PatternManager(zrId, svgRoot);
78 this._clipPathManager = new ClippathManager(zrId, svgRoot);
79 this._shadowManager = new ShadowManager(zrId, svgRoot);
80 var viewport = document.createElement('div');
81 viewport.style.cssText = 'overflow:hidden;position:relative';
82 this._svgDom = svgDom;
83 this._svgRoot = svgRoot;
84 this._backgroundRoot = bgRoot;
85 this._viewport = viewport;
86 root.appendChild(viewport);
87 viewport.appendChild(svgDom);
88 this.resize(opts.width, opts.height);
89 this._visibleList = [];
90 }
91 SVGPainter.prototype.getType = function () {
92 return 'svg';
93 };
94 SVGPainter.prototype.getViewportRoot = function () {
95 return this._viewport;
96 };
97 SVGPainter.prototype.getSvgDom = function () {
98 return this._svgDom;
99 };
100 SVGPainter.prototype.getSvgRoot = function () {
101 return this._svgRoot;
102 };
103 SVGPainter.prototype.getViewportRootOffset = function () {
104 var viewportRoot = this.getViewportRoot();
105 if (viewportRoot) {
106 return {
107 offsetLeft: viewportRoot.offsetLeft || 0,
108 offsetTop: viewportRoot.offsetTop || 0
109 };
110 }
111 };
112 SVGPainter.prototype.refresh = function () {
113 var list = this.storage.getDisplayList(true);
114 this._paintList(list);
115 };
116 SVGPainter.prototype.setBackgroundColor = function (backgroundColor) {
117 if (this._backgroundRoot && this._backgroundNode) {
118 this._backgroundRoot.removeChild(this._backgroundNode);
119 }
120 var bgNode = createElement('rect');
121 bgNode.setAttribute('width', this.getWidth());
122 bgNode.setAttribute('height', this.getHeight());
123 bgNode.setAttribute('x', 0);
124 bgNode.setAttribute('y', 0);
125 bgNode.setAttribute('id', 0);
126 var _a = normalizeColor(backgroundColor), color = _a.color, opacity = _a.opacity;
127 bgNode.setAttribute('fill', color);
128 bgNode.setAttribute('fill-opacity', opacity);
129 this._backgroundRoot.appendChild(bgNode);
130 this._backgroundNode = bgNode;
131 };
132 SVGPainter.prototype.createSVGElement = function (tag) {
133 return createElement(tag);
134 };
135 SVGPainter.prototype.paintOne = function (el) {
136 var svgProxy = getSvgProxy(el);
137 svgProxy && svgProxy.brush(el);
138 return getSvgElement(el);
139 };
140 SVGPainter.prototype._paintList = function (list) {
141 var gradientManager = this._gradientManager;
142 var patternManager = this._patternManager;
143 var clipPathManager = this._clipPathManager;
144 var shadowManager = this._shadowManager;
145 gradientManager.markAllUnused();
146 patternManager.markAllUnused();
147 clipPathManager.markAllUnused();
148 shadowManager.markAllUnused();
149 var svgRoot = this._svgRoot;
150 var visibleList = this._visibleList;
151 var listLen = list.length;
152 var newVisibleList = [];
153 for (var i = 0; i < listLen; i++) {
154 var displayable = list[i];
155 var svgProxy = getSvgProxy(displayable);
156 var svgElement = getSvgElement(displayable);
157 if (!displayable.invisible) {
158 if (displayable.__dirty || !svgElement) {
159 svgProxy && svgProxy.brush(displayable);
160 svgElement = getSvgElement(displayable);
161 if (svgElement && displayable.style) {
162 gradientManager.update(displayable.style.fill);
163 gradientManager.update(displayable.style.stroke);
164 patternManager.update(displayable.style.fill);
165 patternManager.update(displayable.style.stroke);
166 shadowManager.update(svgElement, displayable);
167 }
168 displayable.__dirty = 0;
169 }
170 if (svgElement) {
171 newVisibleList.push(displayable);
172 }
173 }
174 }
175 var diff = arrayDiff(visibleList, newVisibleList);
176 var prevSvgElement;
177 var topPrevSvgElement;
178 for (var i = 0; i < diff.length; i++) {
179 var item = diff[i];
180 if (item.removed) {
181 for (var k = 0; k < item.count; k++) {
182 var displayable = visibleList[item.indices[k]];
183 var svgElement = getSvgElement(displayable);
184 hasClipPath(displayable) ? removeFromMyParent(svgElement)
185 : remove(svgRoot, svgElement);
186 }
187 }
188 }
189 var prevDisplayable;
190 var currentClipGroup;
191 for (var i = 0; i < diff.length; i++) {
192 var item = diff[i];
193 if (item.removed) {
194 continue;
195 }
196 for (var k = 0; k < item.count; k++) {
197 var displayable = newVisibleList[item.indices[k]];
198 var clipGroup = clipPathManager.update(displayable, prevDisplayable);
199 if (clipGroup !== currentClipGroup) {
200 prevSvgElement = topPrevSvgElement;
201 if (clipGroup) {
202 prevSvgElement ? insertAfter(svgRoot, clipGroup, prevSvgElement)
203 : prepend(svgRoot, clipGroup);
204 topPrevSvgElement = clipGroup;
205 prevSvgElement = null;
206 }
207 currentClipGroup = clipGroup;
208 }
209 var svgElement = getSvgElement(displayable);
210 prevSvgElement
211 ? insertAfter(currentClipGroup || svgRoot, svgElement, prevSvgElement)
212 : prepend(currentClipGroup || svgRoot, svgElement);
213 prevSvgElement = svgElement || prevSvgElement;
214 if (!currentClipGroup) {
215 topPrevSvgElement = prevSvgElement;
216 }
217 gradientManager.markUsed(displayable);
218 gradientManager.addWithoutUpdate(svgElement, displayable);
219 patternManager.markUsed(displayable);
220 patternManager.addWithoutUpdate(svgElement, displayable);
221 clipPathManager.markUsed(displayable);
222 prevDisplayable = displayable;
223 }
224 }
225 gradientManager.removeUnused();
226 patternManager.removeUnused();
227 clipPathManager.removeUnused();
228 shadowManager.removeUnused();
229 this._visibleList = newVisibleList;
230 };
231 SVGPainter.prototype.resize = function (width, height) {
232 var viewport = this._viewport;
233 viewport.style.display = 'none';
234 var opts = this._opts;
235 width != null && (opts.width = width);
236 height != null && (opts.height = height);
237 width = getSize(this.root, 0, opts);
238 height = getSize(this.root, 1, opts);
239 viewport.style.display = '';
240 if (this._width !== width || this._height !== height) {
241 this._width = width;
242 this._height = height;
243 var viewportStyle = viewport.style;
244 viewportStyle.width = width + 'px';
245 viewportStyle.height = height + 'px';
246 var svgRoot = this._svgDom;
247 svgRoot.setAttribute('width', width + '');
248 svgRoot.setAttribute('height', height + '');
249 }
250 if (this._backgroundNode) {
251 this._backgroundNode.setAttribute('width', width);
252 this._backgroundNode.setAttribute('height', height);
253 }
254 };
255 SVGPainter.prototype.getWidth = function () {
256 return this._width;
257 };
258 SVGPainter.prototype.getHeight = function () {
259 return this._height;
260 };
261 SVGPainter.prototype.dispose = function () {
262 this.root.innerHTML = '';
263 this._svgRoot =
264 this._backgroundRoot =
265 this._svgDom =
266 this._backgroundNode =
267 this._viewport = this.storage = null;
268 };
269 SVGPainter.prototype.clear = function () {
270 var viewportNode = this._viewport;
271 if (viewportNode && viewportNode.parentNode) {
272 viewportNode.parentNode.removeChild(viewportNode);
273 }
274 };
275 SVGPainter.prototype.toDataURL = function () {
276 this.refresh();
277 var svgDom = this._svgDom;
278 var outerHTML = svgDom.outerHTML
279 || (svgDom.parentNode && svgDom.parentNode.innerHTML);
280 var html = encodeURIComponent(outerHTML.replace(/></g, '>\n\r<'));
281 return 'data:image/svg+xml;charset=UTF-8,' + html;
282 };
283 return SVGPainter;
284}());
285function createMethodNotSupport(method) {
286 return function () {
287 if (process.env.NODE_ENV !== 'production') {
288 util.logError('In SVG mode painter not support method "' + method + '"');
289 }
290 };
291}
292export default SVGPainter;