123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- 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; // displayable.__clipPaths can only be `null`/`undefined` or an non-empty array.
- if (displayable.__clipPaths) {
- 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;
|