| import { |
| extendPrototype, |
| } from '../../utils/functionExtensions'; |
| import { getLocationHref } from '../../main'; |
| import ShapePropertyFactory from '../../utils/shapes/ShapeProperty'; |
| import BaseElement from '../BaseElement'; |
| import TransformElement from '../helpers/TransformElement'; |
| import SVGBaseElement from './SVGBaseElement'; |
| import HierarchyElement from '../helpers/HierarchyElement'; |
| import FrameElement from '../helpers/FrameElement'; |
| import RenderableDOMElement from '../helpers/RenderableDOMElement'; |
| import getBlendMode from '../../utils/helpers/blendModes'; |
| import Matrix from '../../3rd_party/transformation-matrix'; |
| import IShapeElement from '../ShapeElement'; |
| import TransformPropertyFactory from '../../utils/TransformProperty'; |
| import { ShapeModifiers } from '../../utils/shapes/ShapeModifiers'; |
| import { |
| lineCapEnum, |
| lineJoinEnum, |
| } from '../../utils/helpers/shapeEnums'; |
| import SVGShapeData from '../helpers/shapes/SVGShapeData'; |
| import SVGStyleData from '../helpers/shapes/SVGStyleData'; |
| import SVGStrokeStyleData from '../helpers/shapes/SVGStrokeStyleData'; |
| import SVGFillStyleData from '../helpers/shapes/SVGFillStyleData'; |
| import SVGNoStyleData from '../helpers/shapes/SVGNoStyleData'; |
| import SVGGradientFillStyleData from '../helpers/shapes/SVGGradientFillStyleData'; |
| import SVGGradientStrokeStyleData from '../helpers/shapes/SVGGradientStrokeStyleData'; |
| import ShapeGroupData from '../helpers/shapes/ShapeGroupData'; |
| import SVGTransformData from '../helpers/shapes/SVGTransformData'; |
| import SVGElementsRenderer from '../helpers/shapes/SVGElementsRenderer'; |
| |
| function SVGShapeElement(data, globalData, comp) { |
| // List of drawable elements |
| this.shapes = []; |
| // Full shape data |
| this.shapesData = data.shapes; |
| // List of styles that will be applied to shapes |
| this.stylesList = []; |
| // List of modifiers that will be applied to shapes |
| this.shapeModifiers = []; |
| // List of items in shape tree |
| this.itemsData = []; |
| // List of items in previous shape tree |
| this.processedElements = []; |
| // List of animated components |
| this.animatedContents = []; |
| this.initElement(data, globalData, comp); |
| // Moving any property that doesn't get too much access after initialization because of v8 way of handling more than 10 properties. |
| // List of elements that have been created |
| this.prevViewData = []; |
| // Moving any property that doesn't get too much access after initialization because of v8 way of handling more than 10 properties. |
| } |
| |
| extendPrototype([BaseElement, TransformElement, SVGBaseElement, IShapeElement, HierarchyElement, FrameElement, RenderableDOMElement], SVGShapeElement); |
| |
| SVGShapeElement.prototype.initSecondaryElement = function () { |
| }; |
| |
| SVGShapeElement.prototype.identityMatrix = new Matrix(); |
| |
| SVGShapeElement.prototype.buildExpressionInterface = function () {}; |
| |
| SVGShapeElement.prototype.createContent = function () { |
| this.searchShapes(this.shapesData, this.itemsData, this.prevViewData, this.layerElement, 0, [], true); |
| this.filterUniqueShapes(); |
| }; |
| |
| /* |
| This method searches for multiple shapes that affect a single element and one of them is animated |
| */ |
| SVGShapeElement.prototype.filterUniqueShapes = function () { |
| var i; |
| var len = this.shapes.length; |
| var shape; |
| var j; |
| var jLen = this.stylesList.length; |
| var style; |
| var tempShapes = []; |
| var areAnimated = false; |
| for (j = 0; j < jLen; j += 1) { |
| style = this.stylesList[j]; |
| areAnimated = false; |
| tempShapes.length = 0; |
| for (i = 0; i < len; i += 1) { |
| shape = this.shapes[i]; |
| if (shape.styles.indexOf(style) !== -1) { |
| tempShapes.push(shape); |
| areAnimated = shape._isAnimated || areAnimated; |
| } |
| } |
| if (tempShapes.length > 1 && areAnimated) { |
| this.setShapesAsAnimated(tempShapes); |
| } |
| } |
| }; |
| |
| SVGShapeElement.prototype.setShapesAsAnimated = function (shapes) { |
| var i; |
| var len = shapes.length; |
| for (i = 0; i < len; i += 1) { |
| shapes[i].setAsAnimated(); |
| } |
| }; |
| |
| SVGShapeElement.prototype.createStyleElement = function (data, level) { |
| // TODO: prevent drawing of hidden styles |
| var elementData; |
| var styleOb = new SVGStyleData(data, level); |
| |
| var pathElement = styleOb.pElem; |
| if (data.ty === 'st') { |
| elementData = new SVGStrokeStyleData(this, data, styleOb); |
| } else if (data.ty === 'fl') { |
| elementData = new SVGFillStyleData(this, data, styleOb); |
| } else if (data.ty === 'gf' || data.ty === 'gs') { |
| var GradientConstructor = data.ty === 'gf' ? SVGGradientFillStyleData : SVGGradientStrokeStyleData; |
| elementData = new GradientConstructor(this, data, styleOb); |
| this.globalData.defs.appendChild(elementData.gf); |
| if (elementData.maskId) { |
| this.globalData.defs.appendChild(elementData.ms); |
| this.globalData.defs.appendChild(elementData.of); |
| pathElement.setAttribute('mask', 'url(' + getLocationHref() + '#' + elementData.maskId + ')'); |
| } |
| } else if (data.ty === 'no') { |
| elementData = new SVGNoStyleData(this, data, styleOb); |
| } |
| |
| if (data.ty === 'st' || data.ty === 'gs') { |
| pathElement.setAttribute('stroke-linecap', lineCapEnum[data.lc || 2]); |
| pathElement.setAttribute('stroke-linejoin', lineJoinEnum[data.lj || 2]); |
| pathElement.setAttribute('fill-opacity', '0'); |
| if (data.lj === 1) { |
| pathElement.setAttribute('stroke-miterlimit', data.ml); |
| } |
| } |
| |
| if (data.r === 2) { |
| pathElement.setAttribute('fill-rule', 'evenodd'); |
| } |
| |
| if (data.ln) { |
| pathElement.setAttribute('id', data.ln); |
| } |
| if (data.cl) { |
| pathElement.setAttribute('class', data.cl); |
| } |
| if (data.bm) { |
| pathElement.style['mix-blend-mode'] = getBlendMode(data.bm); |
| } |
| this.stylesList.push(styleOb); |
| this.addToAnimatedContents(data, elementData); |
| return elementData; |
| }; |
| |
| SVGShapeElement.prototype.createGroupElement = function (data) { |
| var elementData = new ShapeGroupData(); |
| if (data.ln) { |
| elementData.gr.setAttribute('id', data.ln); |
| } |
| if (data.cl) { |
| elementData.gr.setAttribute('class', data.cl); |
| } |
| if (data.bm) { |
| elementData.gr.style['mix-blend-mode'] = getBlendMode(data.bm); |
| } |
| return elementData; |
| }; |
| |
| SVGShapeElement.prototype.createTransformElement = function (data, container) { |
| var transformProperty = TransformPropertyFactory.getTransformProperty(this, data, this); |
| var elementData = new SVGTransformData(transformProperty, transformProperty.o, container); |
| this.addToAnimatedContents(data, elementData); |
| return elementData; |
| }; |
| |
| SVGShapeElement.prototype.createShapeElement = function (data, ownTransformers, level) { |
| var ty = 4; |
| if (data.ty === 'rc') { |
| ty = 5; |
| } else if (data.ty === 'el') { |
| ty = 6; |
| } else if (data.ty === 'sr') { |
| ty = 7; |
| } |
| var shapeProperty = ShapePropertyFactory.getShapeProp(this, data, ty, this); |
| var elementData = new SVGShapeData(ownTransformers, level, shapeProperty); |
| this.shapes.push(elementData); |
| this.addShapeToModifiers(elementData); |
| this.addToAnimatedContents(data, elementData); |
| return elementData; |
| }; |
| |
| SVGShapeElement.prototype.addToAnimatedContents = function (data, element) { |
| var i = 0; |
| var len = this.animatedContents.length; |
| while (i < len) { |
| if (this.animatedContents[i].element === element) { |
| return; |
| } |
| i += 1; |
| } |
| this.animatedContents.push({ |
| fn: SVGElementsRenderer.createRenderFunction(data), |
| element: element, |
| data: data, |
| }); |
| }; |
| |
| SVGShapeElement.prototype.setElementStyles = function (elementData) { |
| var arr = elementData.styles; |
| var j; |
| var jLen = this.stylesList.length; |
| for (j = 0; j < jLen; j += 1) { |
| if (!this.stylesList[j].closed) { |
| arr.push(this.stylesList[j]); |
| } |
| } |
| }; |
| |
| SVGShapeElement.prototype.reloadShapes = function () { |
| this._isFirstFrame = true; |
| var i; |
| var len = this.itemsData.length; |
| for (i = 0; i < len; i += 1) { |
| this.prevViewData[i] = this.itemsData[i]; |
| } |
| this.searchShapes(this.shapesData, this.itemsData, this.prevViewData, this.layerElement, 0, [], true); |
| this.filterUniqueShapes(); |
| len = this.dynamicProperties.length; |
| for (i = 0; i < len; i += 1) { |
| this.dynamicProperties[i].getValue(); |
| } |
| this.renderModifiers(); |
| }; |
| |
| SVGShapeElement.prototype.searchShapes = function (arr, itemsData, prevViewData, container, level, transformers, render) { |
| var ownTransformers = [].concat(transformers); |
| var i; |
| var len = arr.length - 1; |
| var j; |
| var jLen; |
| var ownStyles = []; |
| var ownModifiers = []; |
| var currentTransform; |
| var modifier; |
| var processedPos; |
| for (i = len; i >= 0; i -= 1) { |
| processedPos = this.searchProcessedElement(arr[i]); |
| if (!processedPos) { |
| arr[i]._render = render; |
| } else { |
| itemsData[i] = prevViewData[processedPos - 1]; |
| } |
| if (arr[i].ty === 'fl' || arr[i].ty === 'st' || arr[i].ty === 'gf' || arr[i].ty === 'gs' || arr[i].ty === 'no') { |
| if (!processedPos) { |
| itemsData[i] = this.createStyleElement(arr[i], level); |
| } else { |
| itemsData[i].style.closed = false; |
| } |
| if (arr[i]._render) { |
| if (itemsData[i].style.pElem.parentNode !== container) { |
| container.appendChild(itemsData[i].style.pElem); |
| } |
| } |
| ownStyles.push(itemsData[i].style); |
| } else if (arr[i].ty === 'gr') { |
| if (!processedPos) { |
| itemsData[i] = this.createGroupElement(arr[i]); |
| } else { |
| jLen = itemsData[i].it.length; |
| for (j = 0; j < jLen; j += 1) { |
| itemsData[i].prevViewData[j] = itemsData[i].it[j]; |
| } |
| } |
| this.searchShapes(arr[i].it, itemsData[i].it, itemsData[i].prevViewData, itemsData[i].gr, level + 1, ownTransformers, render); |
| if (arr[i]._render) { |
| if (itemsData[i].gr.parentNode !== container) { |
| container.appendChild(itemsData[i].gr); |
| } |
| } |
| } else if (arr[i].ty === 'tr') { |
| if (!processedPos) { |
| itemsData[i] = this.createTransformElement(arr[i], container); |
| } |
| currentTransform = itemsData[i].transform; |
| ownTransformers.push(currentTransform); |
| } else if (arr[i].ty === 'sh' || arr[i].ty === 'rc' || arr[i].ty === 'el' || arr[i].ty === 'sr') { |
| if (!processedPos) { |
| itemsData[i] = this.createShapeElement(arr[i], ownTransformers, level); |
| } |
| this.setElementStyles(itemsData[i]); |
| } else if (arr[i].ty === 'tm' || arr[i].ty === 'rd' || arr[i].ty === 'ms' || arr[i].ty === 'pb') { |
| if (!processedPos) { |
| modifier = ShapeModifiers.getModifier(arr[i].ty); |
| modifier.init(this, arr[i]); |
| itemsData[i] = modifier; |
| this.shapeModifiers.push(modifier); |
| } else { |
| modifier = itemsData[i]; |
| modifier.closed = false; |
| } |
| ownModifiers.push(modifier); |
| } else if (arr[i].ty === 'rp') { |
| if (!processedPos) { |
| modifier = ShapeModifiers.getModifier(arr[i].ty); |
| itemsData[i] = modifier; |
| modifier.init(this, arr, i, itemsData); |
| this.shapeModifiers.push(modifier); |
| render = false; |
| } else { |
| modifier = itemsData[i]; |
| modifier.closed = true; |
| } |
| ownModifiers.push(modifier); |
| } |
| this.addProcessedElement(arr[i], i + 1); |
| } |
| len = ownStyles.length; |
| for (i = 0; i < len; i += 1) { |
| ownStyles[i].closed = true; |
| } |
| len = ownModifiers.length; |
| for (i = 0; i < len; i += 1) { |
| ownModifiers[i].closed = true; |
| } |
| }; |
| |
| SVGShapeElement.prototype.renderInnerContent = function () { |
| this.renderModifiers(); |
| var i; |
| var len = this.stylesList.length; |
| for (i = 0; i < len; i += 1) { |
| this.stylesList[i].reset(); |
| } |
| this.renderShape(); |
| for (i = 0; i < len; i += 1) { |
| if (this.stylesList[i]._mdf || this._isFirstFrame) { |
| if (this.stylesList[i].msElem) { |
| this.stylesList[i].msElem.setAttribute('d', this.stylesList[i].d); |
| // Adding M0 0 fixes same mask bug on all browsers |
| this.stylesList[i].d = 'M0 0' + this.stylesList[i].d; |
| } |
| this.stylesList[i].pElem.setAttribute('d', this.stylesList[i].d || 'M0 0'); |
| } |
| } |
| }; |
| |
| SVGShapeElement.prototype.renderShape = function () { |
| var i; |
| var len = this.animatedContents.length; |
| var animatedContent; |
| for (i = 0; i < len; i += 1) { |
| animatedContent = this.animatedContents[i]; |
| if ((this._isFirstFrame || animatedContent.element._isAnimated) && animatedContent.data !== true) { |
| animatedContent.fn(animatedContent.data, animatedContent.element, this._isFirstFrame); |
| } |
| } |
| }; |
| |
| SVGShapeElement.prototype.destroy = function () { |
| this.destroyBaseElement(); |
| this.shapesData = null; |
| this.itemsData = null; |
| }; |
| |
| export default SVGShapeElement; |