| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 | var Definable = require("./Definable");var zrUtil = require("../../core/util");/** * @file Manages SVG shadow elements. * @author Zhang Wenli *//** * Manages SVG shadow elements. * * @class * @extends Definable * @param   {number}     zrId    zrender instance id * @param   {SVGElement} svgRoot root of SVG document */function ShadowManager(zrId, svgRoot) {  Definable.call(this, zrId, svgRoot, ['filter'], '__filter_in_use__', '_shadowDom');}zrUtil.inherits(ShadowManager, Definable);/** * Create new shadow DOM for fill or stroke if not exist, * but will not update shadow if exists. * * @param {SvgElement}  svgElement   SVG element to paint * @param {Displayable} displayable  zrender displayable element */ShadowManager.prototype.addWithoutUpdate = function (svgElement, displayable) {  if (displayable && hasShadow(displayable.style)) {    // Create dom in <defs> if not exists    var dom;    if (displayable._shadowDom) {      // Gradient exists      dom = displayable._shadowDom;      var defs = this.getDefs(true);      if (!defs.contains(displayable._shadowDom)) {        // _shadowDom is no longer in defs, recreate        this.addDom(dom);      }    } else {      // New dom      dom = this.add(displayable);    }    this.markUsed(displayable);    var id = dom.getAttribute('id');    svgElement.style.filter = 'url(#' + id + ')';  }};/** * Add a new shadow tag in <defs> * * @param {Displayable} displayable  zrender displayable element * @return {SVGFilterElement} created DOM */ShadowManager.prototype.add = function (displayable) {  var dom = this.createElement('filter'); // Set dom id with shadow id, since each shadow instance  // will have no more than one dom element.  // id may exists before for those dirty elements, in which case  // id should remain the same, and other attributes should be  // updated.  displayable._shadowDomId = displayable._shadowDomId || this.nextId++;  dom.setAttribute('id', 'zr' + this._zrId + '-shadow-' + displayable._shadowDomId);  this.updateDom(displayable, dom);  this.addDom(dom);  return dom;};/** * Update shadow. * * @param {Displayable} displayable  zrender displayable element */ShadowManager.prototype.update = function (svgElement, displayable) {  var style = displayable.style;  if (hasShadow(style)) {    var that = this;    Definable.prototype.update.call(this, displayable, function () {      that.updateDom(displayable, displayable._shadowDom);    });  } else {    // Remove shadow    this.remove(svgElement, displayable);  }};/** * Remove DOM and clear parent filter */ShadowManager.prototype.remove = function (svgElement, displayable) {  if (displayable._shadowDomId != null) {    this.removeDom(svgElement);    svgElement.style.filter = '';  }};/** * Update shadow dom * * @param {Displayable} displayable  zrender displayable element * @param {SVGFilterElement} dom DOM to update */ShadowManager.prototype.updateDom = function (displayable, dom) {  var domChild = dom.getElementsByTagName('feDropShadow');  if (domChild.length === 0) {    domChild = this.createElement('feDropShadow');  } else {    domChild = domChild[0];  }  var style = displayable.style;  var scaleX = displayable.scale ? displayable.scale[0] || 1 : 1;  var scaleY = displayable.scale ? displayable.scale[1] || 1 : 1; // TODO: textBoxShadowBlur is not supported yet  var offsetX;  var offsetY;  var blur;  var color;  if (style.shadowBlur || style.shadowOffsetX || style.shadowOffsetY) {    offsetX = style.shadowOffsetX || 0;    offsetY = style.shadowOffsetY || 0;    blur = style.shadowBlur;    color = style.shadowColor;  } else if (style.textShadowBlur) {    offsetX = style.textShadowOffsetX || 0;    offsetY = style.textShadowOffsetY || 0;    blur = style.textShadowBlur;    color = style.textShadowColor;  } else {    // Remove shadow    this.removeDom(dom, style);    return;  }  domChild.setAttribute('dx', offsetX / scaleX);  domChild.setAttribute('dy', offsetY / scaleY);  domChild.setAttribute('flood-color', color); // Divide by two here so that it looks the same as in canvas  // See: https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-shadowblur  var stdDx = blur / 2 / scaleX;  var stdDy = blur / 2 / scaleY;  var stdDeviation = stdDx + ' ' + stdDy;  domChild.setAttribute('stdDeviation', stdDeviation); // Fix filter clipping problem  dom.setAttribute('x', '-100%');  dom.setAttribute('y', '-100%');  dom.setAttribute('width', Math.ceil(blur / 2 * 200) + '%');  dom.setAttribute('height', Math.ceil(blur / 2 * 200) + '%');  dom.appendChild(domChild); // Store dom element in shadow, to avoid creating multiple  // dom instances for the same shadow element  displayable._shadowDom = dom;};/** * Mark a single shadow to be used * * @param {Displayable} displayable displayable element */ShadowManager.prototype.markUsed = function (displayable) {  if (displayable._shadowDom) {    Definable.prototype.markUsed.call(this, displayable._shadowDom);  }};function hasShadow(style) {  // TODO: textBoxShadowBlur is not supported yet  return style && (style.shadowBlur || style.shadowOffsetX || style.shadowOffsetY || style.textShadowBlur || style.textShadowOffsetX || style.textShadowOffsetY);}var _default = ShadowManager;module.exports = _default;
 |