| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 | var Definable = require("./Definable");var zrUtil = require("../../core/util");var logError = require("../../core/log");var colorTool = require("../../tool/color");/** * @file Manages SVG gradient elements. * @author Zhang Wenli *//** * Manages SVG gradient elements. * * @class * @extends Definable * @param   {number}     zrId    zrender instance id * @param   {SVGElement} svgRoot root of SVG document */function GradientManager(zrId, svgRoot) {  Definable.call(this, zrId, svgRoot, ['linearGradient', 'radialGradient'], '__gradient_in_use__');}zrUtil.inherits(GradientManager, Definable);/** * Create new gradient DOM for fill or stroke if not exist, * but will not update gradient if exists. * * @param {SvgElement}  svgElement   SVG element to paint * @param {Displayable} displayable  zrender displayable element */GradientManager.prototype.addWithoutUpdate = function (svgElement, displayable) {  if (displayable && displayable.style) {    var that = this;    zrUtil.each(['fill', 'stroke'], function (fillOrStroke) {      if (displayable.style[fillOrStroke] && (displayable.style[fillOrStroke].type === 'linear' || displayable.style[fillOrStroke].type === 'radial')) {        var gradient = displayable.style[fillOrStroke];        var defs = that.getDefs(true); // Create dom in <defs> if not exists        var dom;        if (gradient._dom) {          // Gradient exists          dom = gradient._dom;          if (!defs.contains(gradient._dom)) {            // _dom is no longer in defs, recreate            that.addDom(dom);          }        } else {          // New dom          dom = that.add(gradient);        }        that.markUsed(displayable);        var id = dom.getAttribute('id');        svgElement.setAttribute(fillOrStroke, 'url(#' + id + ')');      }    });  }};/** * Add a new gradient tag in <defs> * * @param   {Gradient} gradient zr gradient instance * @return {SVGLinearGradientElement | SVGRadialGradientElement} *                            created DOM */GradientManager.prototype.add = function (gradient) {  var dom;  if (gradient.type === 'linear') {    dom = this.createElement('linearGradient');  } else if (gradient.type === 'radial') {    dom = this.createElement('radialGradient');  } else {    logError('Illegal gradient type.');    return null;  } // Set dom id with gradient id, since each gradient 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.  gradient.id = gradient.id || this.nextId++;  dom.setAttribute('id', 'zr' + this._zrId + '-gradient-' + gradient.id);  this.updateDom(gradient, dom);  this.addDom(dom);  return dom;};/** * Update gradient. * * @param {Gradient} gradient zr gradient instance */GradientManager.prototype.update = function (gradient) {  var that = this;  Definable.prototype.update.call(this, gradient, function () {    var type = gradient.type;    var tagName = gradient._dom.tagName;    if (type === 'linear' && tagName === 'linearGradient' || type === 'radial' && tagName === 'radialGradient') {      // Gradient type is not changed, update gradient      that.updateDom(gradient, gradient._dom);    } else {      // Remove and re-create if type is changed      that.removeDom(gradient);      that.add(gradient);    }  });};/** * Update gradient dom * * @param {Gradient} gradient zr gradient instance * @param {SVGLinearGradientElement | SVGRadialGradientElement} dom *                            DOM to update */GradientManager.prototype.updateDom = function (gradient, dom) {  if (gradient.type === 'linear') {    dom.setAttribute('x1', gradient.x);    dom.setAttribute('y1', gradient.y);    dom.setAttribute('x2', gradient.x2);    dom.setAttribute('y2', gradient.y2);  } else if (gradient.type === 'radial') {    dom.setAttribute('cx', gradient.x);    dom.setAttribute('cy', gradient.y);    dom.setAttribute('r', gradient.r);  } else {    logError('Illegal gradient type.');    return;  }  if (gradient.global) {    // x1, x2, y1, y2 in range of 0 to canvas width or height    dom.setAttribute('gradientUnits', 'userSpaceOnUse');  } else {    // x1, x2, y1, y2 in range of 0 to 1    dom.setAttribute('gradientUnits', 'objectBoundingBox');  } // Remove color stops if exists  dom.innerHTML = ''; // Add color stops  var colors = gradient.colorStops;  for (var i = 0, len = colors.length; i < len; ++i) {    var stop = this.createElement('stop');    stop.setAttribute('offset', colors[i].offset * 100 + '%');    var color = colors[i].color;    if (color.indexOf('rgba') > -1) {      // Fix Safari bug that stop-color not recognizing alpha #9014      var opacity = colorTool.parse(color)[3];      var hex = colorTool.toHex(color); // stop-color cannot be color, since:      // The opacity value used for the gradient calculation is the      // *product* of the value of stop-opacity and the opacity of the      // value of stop-color.      // See https://www.w3.org/TR/SVG2/pservers.html#StopOpacityProperty      stop.setAttribute('stop-color', '#' + hex);      stop.setAttribute('stop-opacity', opacity);    } else {      stop.setAttribute('stop-color', colors[i].color);    }    dom.appendChild(stop);  } // Store dom element in gradient, to avoid creating multiple  // dom instances for the same gradient element  gradient._dom = dom;};/** * Mark a single gradient to be used * * @param {Displayable} displayable displayable element */GradientManager.prototype.markUsed = function (displayable) {  if (displayable.style) {    var gradient = displayable.style.fill;    if (gradient && gradient._dom) {      Definable.prototype.markUsed.call(this, gradient._dom);    }    gradient = displayable.style.stroke;    if (gradient && gradient._dom) {      Definable.prototype.markUsed.call(this, gradient._dom);    }  }};var _default = GradientManager;module.exports = _default;
 |