Blame view

node_modules/zrender/lib/svg/helper/ClippathManager.js 4.39 KB
aaac7fed   liuqimichale   add
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
  var Definable = require("./Definable");
  
  var zrUtil = require("../../core/util");
  
  var matrix = require("../../core/matrix");
  
  /**
   * @file Manages SVG clipPath elements.
   * @author Zhang Wenli
   */
  
  /**
   * Manages SVG clipPath elements.
   *
   * @class
   * @extends Definable
   * @param   {number}     zrId    zrender instance id
   * @param   {SVGElement} svgRoot root of SVG document
   */
  function ClippathManager(zrId, svgRoot) {
    Definable.call(this, zrId, svgRoot, 'clipPath', '__clippath_in_use__');
  }
  
  zrUtil.inherits(ClippathManager, Definable);
  /**
   * Update clipPath.
   *
   * @param {Displayable} displayable displayable element
   */
  
  ClippathManager.prototype.update = function (displayable) {
    var svgEl = this.getSvgElement(displayable);
  
    if (svgEl) {
      this.updateDom(svgEl, displayable.__clipPaths, false);
    }
  
    var textEl = this.getTextSvgElement(displayable);
  
    if (textEl) {
      // Make another clipPath for text, since it's transform
      // matrix is not the same with svgElement
      this.updateDom(textEl, displayable.__clipPaths, true);
    }
  
    this.markUsed(displayable);
  };
  /**
   * Create an SVGElement of displayable and create a <clipPath> of its
   * clipPath
   *
   * @param {Displayable} parentEl  parent element
   * @param {ClipPath[]}  clipPaths clipPaths of parent element
   * @param {boolean}     isText    if parent element is Text
   */
  
  
  ClippathManager.prototype.updateDom = function (parentEl, clipPaths, isText) {
    if (clipPaths && clipPaths.length > 0) {
      // Has clipPath, create <clipPath> with the first clipPath
      var defs = this.getDefs(true);
      var clipPath = clipPaths[0];
      var clipPathEl;
      var id;
      var dom = isText ? '_textDom' : '_dom';
  
      if (clipPath[dom]) {
        // Use a dom that is already in <defs>
        id = clipPath[dom].getAttribute('id');
        clipPathEl = clipPath[dom]; // Use a dom that is already in <defs>
  
        if (!defs.contains(clipPathEl)) {
          // This happens when set old clipPath that has
          // been previously removed
          defs.appendChild(clipPathEl);
        }
      } else {
        // New <clipPath>
        id = 'zr' + this._zrId + '-clip-' + this.nextId;
        ++this.nextId;
        clipPathEl = this.createElement('clipPath');
        clipPathEl.setAttribute('id', id);
        defs.appendChild(clipPathEl);
        clipPath[dom] = clipPathEl;
      } // Build path and add to <clipPath>
  
  
      var svgProxy = this.getSvgProxy(clipPath);
  
      if (clipPath.transform && clipPath.parent.invTransform && !isText) {
        /**
         * If a clipPath has a parent with transform, the transform
         * of parent should not be considered when setting transform
         * of clipPath. So we need to transform back from parent's
         * transform, which is done by multiplying parent's inverse
         * transform.
         */
        // Store old transform
        var transform = Array.prototype.slice.call(clipPath.transform); // Transform back from parent, and brush path
  
        matrix.mul(clipPath.transform, clipPath.parent.invTransform, clipPath.transform);
        svgProxy.brush(clipPath); // Set back transform of clipPath
  
        clipPath.transform = transform;
      } else {
        svgProxy.brush(clipPath);
      }
  
      var pathEl = this.getSvgElement(clipPath);
      clipPathEl.innerHTML = '';
      /**
       * Use `cloneNode()` here to appendChild to multiple parents,
       * which may happend when Text and other shapes are using the same
       * clipPath. Since Text will create an extra clipPath DOM due to
       * different transform rules.
       */
  
      clipPathEl.appendChild(pathEl.cloneNode());
      parentEl.setAttribute('clip-path', 'url(#' + id + ')');
  
      if (clipPaths.length > 1) {
        // Make the other clipPaths recursively
        this.updateDom(clipPathEl, clipPaths.slice(1), isText);
      }
    } else {
      // No clipPath
      if (parentEl) {
        parentEl.setAttribute('clip-path', 'none');
      }
    }
  };
  /**
   * Mark a single clipPath to be used
   *
   * @param {Displayable} displayable displayable element
   */
  
  
  ClippathManager.prototype.markUsed = function (displayable) {
    var that = this;
  
    if (displayable.__clipPaths && displayable.__clipPaths.length > 0) {
      zrUtil.each(displayable.__clipPaths, function (clipPath) {
        if (clipPath._dom) {
          Definable.prototype.markUsed.call(that, clipPath._dom);
        }
  
        if (clipPath._textDom) {
          Definable.prototype.markUsed.call(that, clipPath._textDom);
        }
      });
    }
  };
  
  var _default = ClippathManager;
  module.exports = _default;