123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402 |
- var _core = require("./core");
- var createElement = _core.createElement;
- var util = require("../core/util");
- var logError = require("../core/log");
- var Path = require("../graphic/Path");
- var ZImage = require("../graphic/Image");
- var ZText = require("../graphic/Text");
- var arrayDiff = require("../core/arrayDiff2");
- var GradientManager = require("./helper/GradientManager");
- var ClippathManager = require("./helper/ClippathManager");
- var ShadowManager = require("./helper/ShadowManager");
- var _graphic = require("./graphic");
- var svgPath = _graphic.path;
- var svgImage = _graphic.image;
- var svgText = _graphic.text;
- /**
- * SVG Painter
- * @module zrender/svg/Painter
- */
- function parseInt10(val) {
- return parseInt(val, 10);
- }
- function getSvgProxy(el) {
- if (el instanceof Path) {
- return svgPath;
- } else if (el instanceof ZImage) {
- return svgImage;
- } else if (el instanceof ZText) {
- return svgText;
- } else {
- return svgPath;
- }
- }
- function checkParentAvailable(parent, child) {
- return child && parent && child.parentNode !== parent;
- }
- function insertAfter(parent, child, prevSibling) {
- if (checkParentAvailable(parent, child) && prevSibling) {
- var nextSibling = prevSibling.nextSibling;
- nextSibling ? parent.insertBefore(child, nextSibling) : parent.appendChild(child);
- }
- }
- function prepend(parent, child) {
- if (checkParentAvailable(parent, child)) {
- var firstChild = parent.firstChild;
- firstChild ? parent.insertBefore(child, firstChild) : parent.appendChild(child);
- }
- } // function append(parent, child) {
- // if (checkParentAvailable(parent, child)) {
- // parent.appendChild(child);
- // }
- // }
- function remove(parent, child) {
- if (child && parent && child.parentNode === parent) {
- parent.removeChild(child);
- }
- }
- function getTextSvgElement(displayable) {
- return displayable.__textSvgEl;
- }
- function getSvgElement(displayable) {
- return displayable.__svgEl;
- }
- /**
- * @alias module:zrender/svg/Painter
- * @constructor
- * @param {HTMLElement} root 绘图容器
- * @param {module:zrender/Storage} storage
- * @param {Object} opts
- */
- var SVGPainter = function (root, storage, opts, zrId) {
- this.root = root;
- this.storage = storage;
- this._opts = opts = util.extend({}, opts || {});
- var svgDom = createElement('svg');
- svgDom.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
- svgDom.setAttribute('version', '1.1');
- svgDom.setAttribute('baseProfile', 'full');
- svgDom.style.cssText = 'user-select:none;position:absolute;left:0;top:0;';
- var bgRoot = createElement('g');
- svgDom.appendChild(bgRoot);
- var svgRoot = createElement('g');
- svgDom.appendChild(svgRoot);
- this.gradientManager = new GradientManager(zrId, svgRoot);
- this.clipPathManager = new ClippathManager(zrId, svgRoot);
- this.shadowManager = new ShadowManager(zrId, svgRoot);
- var viewport = document.createElement('div');
- viewport.style.cssText = 'overflow:hidden;position:relative';
- this._svgDom = svgDom;
- this._svgRoot = svgRoot;
- this._backgroundRoot = bgRoot;
- this._viewport = viewport;
- root.appendChild(viewport);
- viewport.appendChild(svgDom);
- this.resize(opts.width, opts.height);
- this._visibleList = [];
- };
- SVGPainter.prototype = {
- constructor: SVGPainter,
- getType: function () {
- return 'svg';
- },
- getViewportRoot: function () {
- return this._viewport;
- },
- getSvgDom: function () {
- return this._svgDom;
- },
- getSvgRoot: function () {
- return this._svgRoot;
- },
- getViewportRootOffset: function () {
- var viewportRoot = this.getViewportRoot();
- if (viewportRoot) {
- return {
- offsetLeft: viewportRoot.offsetLeft || 0,
- offsetTop: viewportRoot.offsetTop || 0
- };
- }
- },
- refresh: function () {
- var list = this.storage.getDisplayList(true);
- this._paintList(list);
- },
- setBackgroundColor: function (backgroundColor) {
- // TODO gradient
- // Insert a bg rect instead of setting background to viewport.
- // Otherwise, the exported SVG don't have background.
- if (this._backgroundRoot && this._backgroundNode) {
- this._backgroundRoot.removeChild(this._backgroundNode);
- }
- var bgNode = createElement('rect');
- bgNode.setAttribute('width', this.getWidth());
- bgNode.setAttribute('height', this.getHeight());
- bgNode.setAttribute('x', 0);
- bgNode.setAttribute('y', 0);
- bgNode.setAttribute('id', 0);
- bgNode.style.fill = backgroundColor;
- this._backgroundRoot.appendChild(bgNode);
- this._backgroundNode = bgNode;
- },
- _paintList: function (list) {
- this.gradientManager.markAllUnused();
- this.clipPathManager.markAllUnused();
- this.shadowManager.markAllUnused();
- var svgRoot = this._svgRoot;
- var visibleList = this._visibleList;
- var listLen = list.length;
- var newVisibleList = [];
- var i;
- for (i = 0; i < listLen; i++) {
- var displayable = list[i];
- var svgProxy = getSvgProxy(displayable);
- var svgElement = getSvgElement(displayable) || getTextSvgElement(displayable);
- if (!displayable.invisible) {
- if (displayable.__dirty) {
- svgProxy && svgProxy.brush(displayable); // Update clipPath
- this.clipPathManager.update(displayable); // Update gradient and shadow
- if (displayable.style) {
- this.gradientManager.update(displayable.style.fill);
- this.gradientManager.update(displayable.style.stroke);
- this.shadowManager.update(svgElement, displayable);
- }
- displayable.__dirty = false;
- }
- newVisibleList.push(displayable);
- }
- }
- var diff = arrayDiff(visibleList, newVisibleList);
- var prevSvgElement; // First do remove, in case element moved to the head and do remove
- // after add
- for (i = 0; i < diff.length; i++) {
- var item = diff[i];
- if (item.removed) {
- for (var k = 0; k < item.count; k++) {
- var displayable = visibleList[item.indices[k]];
- var svgElement = getSvgElement(displayable);
- var textSvgElement = getTextSvgElement(displayable);
- remove(svgRoot, svgElement);
- remove(svgRoot, textSvgElement);
- }
- }
- }
- for (i = 0; i < diff.length; i++) {
- var item = diff[i];
- if (item.added) {
- for (var k = 0; k < item.count; k++) {
- var displayable = newVisibleList[item.indices[k]];
- var svgElement = getSvgElement(displayable);
- var textSvgElement = getTextSvgElement(displayable);
- prevSvgElement ? insertAfter(svgRoot, svgElement, prevSvgElement) : prepend(svgRoot, svgElement);
- if (svgElement) {
- insertAfter(svgRoot, textSvgElement, svgElement);
- } else if (prevSvgElement) {
- insertAfter(svgRoot, textSvgElement, prevSvgElement);
- } else {
- prepend(svgRoot, textSvgElement);
- } // Insert text
- insertAfter(svgRoot, textSvgElement, svgElement);
- prevSvgElement = textSvgElement || svgElement || prevSvgElement; // zrender.Text only create textSvgElement.
- this.gradientManager.addWithoutUpdate(svgElement || textSvgElement, displayable);
- this.shadowManager.addWithoutUpdate(svgElement || textSvgElement, displayable);
- this.clipPathManager.markUsed(displayable);
- }
- } else if (!item.removed) {
- for (var k = 0; k < item.count; k++) {
- var displayable = newVisibleList[item.indices[k]];
- var svgElement = getSvgElement(displayable);
- var textSvgElement = getTextSvgElement(displayable);
- var svgElement = getSvgElement(displayable);
- var textSvgElement = getTextSvgElement(displayable);
- this.gradientManager.markUsed(displayable);
- this.gradientManager.addWithoutUpdate(svgElement || textSvgElement, displayable);
- this.shadowManager.markUsed(displayable);
- this.shadowManager.addWithoutUpdate(svgElement || textSvgElement, displayable);
- this.clipPathManager.markUsed(displayable);
- if (textSvgElement) {
- // Insert text.
- insertAfter(svgRoot, textSvgElement, svgElement);
- }
- prevSvgElement = svgElement || textSvgElement || prevSvgElement;
- }
- }
- }
- this.gradientManager.removeUnused();
- this.clipPathManager.removeUnused();
- this.shadowManager.removeUnused();
- this._visibleList = newVisibleList;
- },
- _getDefs: function (isForceCreating) {
- var svgRoot = this._svgDom;
- var defs = svgRoot.getElementsByTagName('defs');
- if (defs.length === 0) {
- // Not exist
- if (isForceCreating) {
- var defs = svgRoot.insertBefore(createElement('defs'), // Create new tag
- svgRoot.firstChild // Insert in the front of svg
- );
- if (!defs.contains) {
- // IE doesn't support contains method
- defs.contains = function (el) {
- var children = defs.children;
- if (!children) {
- return false;
- }
- for (var i = children.length - 1; i >= 0; --i) {
- if (children[i] === el) {
- return true;
- }
- }
- return false;
- };
- }
- return defs;
- } else {
- return null;
- }
- } else {
- return defs[0];
- }
- },
- resize: function (width, height) {
- var viewport = this._viewport; // FIXME Why ?
- viewport.style.display = 'none'; // Save input w/h
- var opts = this._opts;
- width != null && (opts.width = width);
- height != null && (opts.height = height);
- width = this._getSize(0);
- height = this._getSize(1);
- viewport.style.display = '';
- if (this._width !== width || this._height !== height) {
- this._width = width;
- this._height = height;
- var viewportStyle = viewport.style;
- viewportStyle.width = width + 'px';
- viewportStyle.height = height + 'px';
- var svgRoot = this._svgDom; // Set width by 'svgRoot.width = width' is invalid
- svgRoot.setAttribute('width', width);
- svgRoot.setAttribute('height', height);
- }
- if (this._backgroundNode) {
- this._backgroundNode.setAttribute('width', width);
- this._backgroundNode.setAttribute('height', height);
- }
- },
- /**
- * 获取绘图区域宽度
- */
- getWidth: function () {
- return this._width;
- },
- /**
- * 获取绘图区域高度
- */
- getHeight: function () {
- return this._height;
- },
- _getSize: function (whIdx) {
- var opts = this._opts;
- var wh = ['width', 'height'][whIdx];
- var cwh = ['clientWidth', 'clientHeight'][whIdx];
- var plt = ['paddingLeft', 'paddingTop'][whIdx];
- var prb = ['paddingRight', 'paddingBottom'][whIdx];
- if (opts[wh] != null && opts[wh] !== 'auto') {
- return parseFloat(opts[wh]);
- }
- var root = this.root; // IE8 does not support getComputedStyle, but it use VML.
- var stl = document.defaultView.getComputedStyle(root);
- return (root[cwh] || parseInt10(stl[wh]) || parseInt10(root.style[wh])) - (parseInt10(stl[plt]) || 0) - (parseInt10(stl[prb]) || 0) | 0;
- },
- dispose: function () {
- this.root.innerHTML = '';
- this._svgRoot = this._backgroundRoot = this._svgDom = this._backgroundNode = this._viewport = this.storage = null;
- },
- clear: function () {
- if (this._viewport) {
- this.root.removeChild(this._viewport);
- }
- },
- toDataURL: function () {
- this.refresh();
- var html = encodeURIComponent(this._svgDom.outerHTML.replace(/></g, '>\n\r<'));
- return 'data:image/svg+xml;charset=UTF-8,' + html;
- }
- }; // Not supported methods
- function createMethodNotSupport(method) {
- return function () {
- logError('In SVG mode painter not support method "' + method + '"');
- };
- } // Unsuppoted methods
- util.each(['getLayer', 'insertLayer', 'eachLayer', 'eachBuiltinLayer', 'eachOtherLayer', 'getLayers', 'modLayer', 'delLayer', 'clearLayer', 'pathToImage'], function (name) {
- SVGPainter.prototype[name] = createMethodNotSupport(name);
- });
- var _default = SVGPainter;
- module.exports = _default;
|