GradientManager.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. var Definable = require("./Definable");
  2. var zrUtil = require("../../core/util");
  3. var zrLog = require("../../core/log");
  4. /**
  5. * @file Manages SVG gradient elements.
  6. * @author Zhang Wenli
  7. */
  8. /**
  9. * Manages SVG gradient elements.
  10. *
  11. * @class
  12. * @extends Definable
  13. * @param {SVGElement} svgRoot root of SVG document
  14. */
  15. function GradientManager(svgRoot) {
  16. Definable.call(this, svgRoot, ['linearGradient', 'radialGradient'], '__gradient_in_use__');
  17. }
  18. zrUtil.inherits(GradientManager, Definable);
  19. /**
  20. * Create new gradient DOM for fill or stroke if not exist,
  21. * but will not update gradient if exists.
  22. *
  23. * @param {SvgElement} svgElement SVG element to paint
  24. * @param {Displayable} displayable zrender displayable element
  25. */
  26. GradientManager.prototype.addWithoutUpdate = function (svgElement, displayable) {
  27. if (displayable && displayable.style) {
  28. var that = this;
  29. zrUtil.each(['fill', 'stroke'], function (fillOrStroke) {
  30. if (displayable.style[fillOrStroke] && (displayable.style[fillOrStroke].type === 'linear' || displayable.style[fillOrStroke].type === 'radial')) {
  31. var gradient = displayable.style[fillOrStroke];
  32. var defs = that.getDefs(true); // Create dom in <defs> if not exists
  33. var dom;
  34. if (gradient._dom) {
  35. // Gradient exists
  36. dom = gradient._dom;
  37. if (!defs.contains(gradient._dom)) {
  38. // _dom is no longer in defs, recreate
  39. that.addDom(dom);
  40. }
  41. } else {
  42. // New dom
  43. dom = that.add(gradient);
  44. }
  45. that.markUsed(displayable);
  46. var id = dom.getAttribute('id');
  47. svgElement.setAttribute(fillOrStroke, 'url(#' + id + ')');
  48. }
  49. });
  50. }
  51. };
  52. /**
  53. * Add a new gradient tag in <defs>
  54. *
  55. * @param {Gradient} gradient zr gradient instance
  56. * @return {SVGLinearGradientElement | SVGRadialGradientElement}
  57. * created DOM
  58. */
  59. GradientManager.prototype.add = function (gradient) {
  60. var dom;
  61. if (gradient.type === 'linear') {
  62. dom = this.createElement('linearGradient');
  63. } else if (gradient.type === 'radial') {
  64. dom = this.createElement('radialGradient');
  65. } else {
  66. zrLog('Illegal gradient type.');
  67. return null;
  68. } // Set dom id with gradient id, since each gradient instance
  69. // will have no more than one dom element.
  70. // id may exists before for those dirty elements, in which case
  71. // id should remain the same, and other attributes should be
  72. // updated.
  73. gradient.id = gradient.id || this.nextId++;
  74. dom.setAttribute('id', 'zr-gradient-' + gradient.id);
  75. this.updateDom(gradient, dom);
  76. this.addDom(dom);
  77. return dom;
  78. };
  79. /**
  80. * Update gradient.
  81. *
  82. * @param {Gradient} gradient zr gradient instance
  83. */
  84. GradientManager.prototype.update = function (gradient) {
  85. var that = this;
  86. Definable.prototype.update.call(this, gradient, function () {
  87. var type = gradient.type;
  88. var tagName = gradient._dom.tagName;
  89. if (type === 'linear' && tagName === 'linearGradient' || type === 'radial' && tagName === 'radialGradient') {
  90. // Gradient type is not changed, update gradient
  91. that.updateDom(gradient, gradient._dom);
  92. } else {
  93. // Remove and re-create if type is changed
  94. that.removeDom(gradient);
  95. that.add(gradient);
  96. }
  97. });
  98. };
  99. /**
  100. * Update gradient dom
  101. *
  102. * @param {Gradient} gradient zr gradient instance
  103. * @param {SVGLinearGradientElement | SVGRadialGradientElement} dom
  104. * DOM to update
  105. */
  106. GradientManager.prototype.updateDom = function (gradient, dom) {
  107. if (gradient.type === 'linear') {
  108. dom.setAttribute('x1', gradient.x);
  109. dom.setAttribute('y1', gradient.y);
  110. dom.setAttribute('x2', gradient.x2);
  111. dom.setAttribute('y2', gradient.y2);
  112. } else if (gradient.type === 'radial') {
  113. dom.setAttribute('cx', gradient.x);
  114. dom.setAttribute('cy', gradient.y);
  115. dom.setAttribute('r', gradient.r);
  116. } else {
  117. zrLog('Illegal gradient type.');
  118. return;
  119. }
  120. if (gradient.global) {
  121. // x1, x2, y1, y2 in range of 0 to canvas width or height
  122. dom.setAttribute('gradientUnits', 'userSpaceOnUse');
  123. } else {
  124. // x1, x2, y1, y2 in range of 0 to 1
  125. dom.setAttribute('gradientUnits', 'objectBoundingBox');
  126. } // Remove color stops if exists
  127. dom.innerHTML = ''; // Add color stops
  128. var colors = gradient.colorStops;
  129. for (var i = 0, len = colors.length; i < len; ++i) {
  130. var stop = this.createElement('stop');
  131. stop.setAttribute('offset', colors[i].offset * 100 + '%');
  132. stop.setAttribute('stop-color', colors[i].color);
  133. dom.appendChild(stop);
  134. } // Store dom element in gradient, to avoid creating multiple
  135. // dom instances for the same gradient element
  136. gradient._dom = dom;
  137. };
  138. /**
  139. * Mark a single gradient to be used
  140. *
  141. * @param {Displayable} displayable displayable element
  142. */
  143. GradientManager.prototype.markUsed = function (displayable) {
  144. if (displayable.style) {
  145. var gradient = displayable.style.fill;
  146. if (gradient && gradient._dom) {
  147. Definable.prototype.markUsed.call(this, gradient._dom);
  148. }
  149. gradient = displayable.style.stroke;
  150. if (gradient && gradient._dom) {
  151. Definable.prototype.markUsed.call(this, gradient._dom);
  152. }
  153. }
  154. };
  155. var _default = GradientManager;
  156. module.exports = _default;