import { brush, setClipPath, setGradient, setPattern } from './graphic.js'; import { createElement, createVNode, vNodeToString, getCssString, createBrushScope, createSVGVNode } from './core.js'; import { normalizeColor, encodeBase64, isGradient, isPattern } from './helper.js'; import { extend, keys, logError, map, noop, retrieve2 } from '../core/util.js'; import patch, { updateAttrs } from './patch.js'; import { getSize } from '../canvas/helper.js'; var svgId = 0; var SVGPainter = (function () { function SVGPainter(root, storage, opts) { this.type = 'svg'; this.refreshHover = createMethodNotSupport('refreshHover'); this.configLayer = createMethodNotSupport('configLayer'); this.storage = storage; this._opts = opts = extend({}, opts); this.root = root; this._id = 'zr' + svgId++; this._oldVNode = createSVGVNode(opts.width, opts.height); if (root && !opts.ssr) { var viewport = this._viewport = document.createElement('div'); viewport.style.cssText = 'position:relative;overflow:hidden'; var svgDom = this._svgDom = this._oldVNode.elm = createElement('svg'); updateAttrs(null, this._oldVNode); viewport.appendChild(svgDom); root.appendChild(viewport); } this.resize(opts.width, opts.height); } SVGPainter.prototype.getType = function () { return this.type; }; SVGPainter.prototype.getViewportRoot = function () { return this._viewport; }; SVGPainter.prototype.getViewportRootOffset = function () { var viewportRoot = this.getViewportRoot(); if (viewportRoot) { return { offsetLeft: viewportRoot.offsetLeft || 0, offsetTop: viewportRoot.offsetTop || 0 }; } }; SVGPainter.prototype.getSvgDom = function () { return this._svgDom; }; SVGPainter.prototype.refresh = function () { if (this.root) { var vnode = this.renderToVNode({ willUpdate: true }); vnode.attrs.style = 'position:absolute;left:0;top:0;user-select:none'; patch(this._oldVNode, vnode); this._oldVNode = vnode; } }; SVGPainter.prototype.renderOneToVNode = function (el) { return brush(el, createBrushScope(this._id)); }; SVGPainter.prototype.renderToVNode = function (opts) { opts = opts || {}; var list = this.storage.getDisplayList(true); var width = this._width; var height = this._height; var scope = createBrushScope(this._id); scope.animation = opts.animation; scope.willUpdate = opts.willUpdate; scope.compress = opts.compress; scope.emphasis = opts.emphasis; var children = []; var bgVNode = this._bgVNode = createBackgroundVNode(width, height, this._backgroundColor, scope); bgVNode && children.push(bgVNode); var mainVNode = !opts.compress ? (this._mainVNode = createVNode('g', 'main', {}, [])) : null; this._paintList(list, scope, mainVNode ? mainVNode.children : children); mainVNode && children.push(mainVNode); var defs = map(keys(scope.defs), function (id) { return scope.defs[id]; }); if (defs.length) { children.push(createVNode('defs', 'defs', {}, defs)); } if (opts.animation) { var animationCssStr = getCssString(scope.cssNodes, scope.cssAnims, { newline: true }); if (animationCssStr) { var styleNode = createVNode('style', 'stl', {}, [], animationCssStr); children.push(styleNode); } } return createSVGVNode(width, height, children, opts.useViewBox); }; SVGPainter.prototype.renderToString = function (opts) { opts = opts || {}; return vNodeToString(this.renderToVNode({ animation: retrieve2(opts.cssAnimation, true), emphasis: retrieve2(opts.cssEmphasis, true), willUpdate: false, compress: true, useViewBox: retrieve2(opts.useViewBox, true) }), { newline: true }); }; SVGPainter.prototype.setBackgroundColor = function (backgroundColor) { this._backgroundColor = backgroundColor; }; SVGPainter.prototype.getSvgRoot = function () { return this._mainVNode && this._mainVNode.elm; }; SVGPainter.prototype._paintList = function (list, scope, out) { var listLen = list.length; var clipPathsGroupsStack = []; var clipPathsGroupsStackDepth = 0; var currentClipPathGroup; var prevClipPaths; var clipGroupNodeIdx = 0; for (var i = 0; i < listLen; i++) { var displayable = list[i]; if (!displayable.invisible) { var clipPaths = displayable.__clipPaths; var len = clipPaths && clipPaths.length || 0; var prevLen = prevClipPaths && prevClipPaths.length || 0; var lca = void 0; for (lca = Math.max(len - 1, prevLen - 1); lca >= 0; lca--) { if (clipPaths && prevClipPaths && clipPaths[lca] === prevClipPaths[lca]) { break; } } for (var i_1 = prevLen - 1; i_1 > lca; i_1--) { clipPathsGroupsStackDepth--; currentClipPathGroup = clipPathsGroupsStack[clipPathsGroupsStackDepth - 1]; } for (var i_2 = lca + 1; i_2 < len; i_2++) { var groupAttrs = {}; setClipPath(clipPaths[i_2], groupAttrs, scope); var g = createVNode('g', 'clip-g-' + clipGroupNodeIdx++, groupAttrs, []); (currentClipPathGroup ? currentClipPathGroup.children : out).push(g); clipPathsGroupsStack[clipPathsGroupsStackDepth++] = g; currentClipPathGroup = g; } prevClipPaths = clipPaths; var ret = brush(displayable, scope); if (ret) { (currentClipPathGroup ? currentClipPathGroup.children : out).push(ret); } } } }; SVGPainter.prototype.resize = function (width, height) { var opts = this._opts; var root = this.root; var viewport = this._viewport; width != null && (opts.width = width); height != null && (opts.height = height); if (root && viewport) { viewport.style.display = 'none'; width = getSize(root, 0, opts); height = getSize(root, 1, opts); viewport.style.display = ''; } if (this._width !== width || this._height !== height) { this._width = width; this._height = height; if (viewport) { var viewportStyle = viewport.style; viewportStyle.width = width + 'px'; viewportStyle.height = height + 'px'; } if (!isPattern(this._backgroundColor)) { var svgDom = this._svgDom; if (svgDom) { svgDom.setAttribute('width', width); svgDom.setAttribute('height', height); } var bgEl = this._bgVNode && this._bgVNode.elm; if (bgEl) { bgEl.setAttribute('width', width); bgEl.setAttribute('height', height); } } else { this.refresh(); } } }; SVGPainter.prototype.getWidth = function () { return this._width; }; SVGPainter.prototype.getHeight = function () { return this._height; }; SVGPainter.prototype.dispose = function () { if (this.root) { this.root.innerHTML = ''; } this._svgDom = this._viewport = this.storage = this._oldVNode = this._bgVNode = this._mainVNode = null; }; SVGPainter.prototype.clear = function () { if (this._svgDom) { this._svgDom.innerHTML = null; } this._oldVNode = null; }; SVGPainter.prototype.toDataURL = function (base64) { var str = this.renderToString(); var prefix = 'data:image/svg+xml;'; if (base64) { str = encodeBase64(str); return str && prefix + 'base64,' + str; } return prefix + 'charset=UTF-8,' + encodeURIComponent(str); }; return SVGPainter; }()); function createMethodNotSupport(method) { return function () { if (process.env.NODE_ENV !== 'production') { logError('In SVG mode painter not support method "' + method + '"'); } }; } function createBackgroundVNode(width, height, backgroundColor, scope) { var bgVNode; if (backgroundColor && backgroundColor !== 'none') { bgVNode = createVNode('rect', 'bg', { width: width, height: height, x: '0', y: '0' }); if (isGradient(backgroundColor)) { setGradient({ fill: backgroundColor }, bgVNode.attrs, 'fill', scope); } else if (isPattern(backgroundColor)) { setPattern({ style: { fill: backgroundColor }, dirty: noop, getBoundingRect: function () { return ({ width: width, height: height }); } }, bgVNode.attrs, 'fill', scope); } else { var _a = normalizeColor(backgroundColor), color = _a.color, opacity = _a.opacity; bgVNode.attrs.fill = color; opacity < 1 && (bgVNode.attrs['fill-opacity'] = opacity); } } return bgVNode; } export default SVGPainter;