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;
|