123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322 |
- import {
- extendPrototype,
- } from '../../utils/functionExtensions';
- import {
- createSizedArray,
- } from '../../utils/helpers/arrays';
- import createNS from '../../utils/helpers/svg_elements';
- 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 ITextElement from '../TextElement';
- import SVGCompElement from './SVGCompElement'; // eslint-disable-line
- import SVGShapeElement from './SVGShapeElement';
- var emptyShapeData = {
- shapes: [],
- };
- function SVGTextLottieElement(data, globalData, comp) {
- this.textSpans = [];
- this.renderType = 'svg';
- this.initElement(data, globalData, comp);
- }
- extendPrototype([BaseElement, TransformElement, SVGBaseElement, HierarchyElement, FrameElement, RenderableDOMElement, ITextElement], SVGTextLottieElement);
- SVGTextLottieElement.prototype.createContent = function () {
- if (this.data.singleShape && !this.globalData.fontManager.chars) {
- this.textContainer = createNS('text');
- }
- };
- SVGTextLottieElement.prototype.buildTextContents = function (textArray) {
- var i = 0;
- var len = textArray.length;
- var textContents = [];
- var currentTextContent = '';
- while (i < len) {
- if (textArray[i] === String.fromCharCode(13) || textArray[i] === String.fromCharCode(3)) {
- textContents.push(currentTextContent);
- currentTextContent = '';
- } else {
- currentTextContent += textArray[i];
- }
- i += 1;
- }
- textContents.push(currentTextContent);
- return textContents;
- };
- SVGTextLottieElement.prototype.buildShapeData = function (data, scale) {
- // data should probably be cloned to apply scale separately to each instance of a text on different layers
- // but since text internal content gets only rendered once and then it's never rerendered,
- // it's probably safe not to clone data and reuse always the same instance even if the object is mutated.
- // Avoiding cloning is preferred since cloning each character shape data is expensive
- if (data.shapes && data.shapes.length) {
- var shape = data.shapes[0];
- if (shape.it) {
- var shapeItem = shape.it[shape.it.length - 1];
- if (shapeItem.s) {
- shapeItem.s.k[0] = scale;
- shapeItem.s.k[1] = scale;
- }
- }
- }
- return data;
- };
- SVGTextLottieElement.prototype.buildNewText = function () {
- this.addDynamicProperty(this);
- var i;
- var len;
- var documentData = this.textProperty.currentData;
- this.renderedLetters = createSizedArray(documentData ? documentData.l.length : 0);
- if (documentData.fc) {
- this.layerElement.setAttribute('fill', this.buildColor(documentData.fc));
- } else {
- this.layerElement.setAttribute('fill', 'rgba(0,0,0,0)');
- }
- if (documentData.sc) {
- this.layerElement.setAttribute('stroke', this.buildColor(documentData.sc));
- this.layerElement.setAttribute('stroke-width', documentData.sw);
- }
- this.layerElement.setAttribute('font-size', documentData.finalSize);
- var fontData = this.globalData.fontManager.getFontByName(documentData.f);
- if (fontData.fClass) {
- this.layerElement.setAttribute('class', fontData.fClass);
- } else {
- this.layerElement.setAttribute('font-family', fontData.fFamily);
- var fWeight = documentData.fWeight;
- var fStyle = documentData.fStyle;
- this.layerElement.setAttribute('font-style', fStyle);
- this.layerElement.setAttribute('font-weight', fWeight);
- }
- this.layerElement.setAttribute('aria-label', documentData.t);
- var letters = documentData.l || [];
- var usesGlyphs = !!this.globalData.fontManager.chars;
- len = letters.length;
- var tSpan;
- var matrixHelper = this.mHelper;
- var shapeStr = '';
- var singleShape = this.data.singleShape;
- var xPos = 0;
- var yPos = 0;
- var firstLine = true;
- var trackingOffset = documentData.tr * 0.001 * documentData.finalSize;
- if (singleShape && !usesGlyphs && !documentData.sz) {
- var tElement = this.textContainer;
- var justify = 'start';
- switch (documentData.j) {
- case 1:
- justify = 'end';
- break;
- case 2:
- justify = 'middle';
- break;
- default:
- justify = 'start';
- break;
- }
- tElement.setAttribute('text-anchor', justify);
- tElement.setAttribute('letter-spacing', trackingOffset);
- var textContent = this.buildTextContents(documentData.finalText);
- len = textContent.length;
- yPos = documentData.ps ? documentData.ps[1] + documentData.ascent : 0;
- for (i = 0; i < len; i += 1) {
- tSpan = this.textSpans[i].span || createNS('tspan');
- tSpan.textContent = textContent[i];
- tSpan.setAttribute('x', 0);
- tSpan.setAttribute('y', yPos);
- tSpan.style.display = 'inherit';
- tElement.appendChild(tSpan);
- if (!this.textSpans[i]) {
- this.textSpans[i] = {
- span: null,
- glyph: null,
- };
- }
- this.textSpans[i].span = tSpan;
- yPos += documentData.finalLineHeight;
- }
- this.layerElement.appendChild(tElement);
- } else {
- var cachedSpansLength = this.textSpans.length;
- var charData;
- for (i = 0; i < len; i += 1) {
- if (!this.textSpans[i]) {
- this.textSpans[i] = {
- span: null,
- childSpan: null,
- glyph: null,
- };
- }
- if (!usesGlyphs || !singleShape || i === 0) {
- tSpan = cachedSpansLength > i ? this.textSpans[i].span : createNS(usesGlyphs ? 'g' : 'text');
- if (cachedSpansLength <= i) {
- tSpan.setAttribute('stroke-linecap', 'butt');
- tSpan.setAttribute('stroke-linejoin', 'round');
- tSpan.setAttribute('stroke-miterlimit', '4');
- this.textSpans[i].span = tSpan;
- if (usesGlyphs) {
- var childSpan = createNS('g');
- tSpan.appendChild(childSpan);
- this.textSpans[i].childSpan = childSpan;
- }
- this.textSpans[i].span = tSpan;
- this.layerElement.appendChild(tSpan);
- }
- tSpan.style.display = 'inherit';
- }
- matrixHelper.reset();
- if (singleShape) {
- if (letters[i].n) {
- xPos = -trackingOffset;
- yPos += documentData.yOffset;
- yPos += firstLine ? 1 : 0;
- firstLine = false;
- }
- this.applyTextPropertiesToMatrix(documentData, matrixHelper, letters[i].line, xPos, yPos);
- xPos += letters[i].l || 0;
- // xPos += letters[i].val === ' ' ? 0 : trackingOffset;
- xPos += trackingOffset;
- }
- if (usesGlyphs) {
- charData = this.globalData.fontManager.getCharData(
- documentData.finalText[i],
- fontData.fStyle,
- this.globalData.fontManager.getFontByName(documentData.f).fFamily
- );
- var glyphElement;
- // t === 1 means the character has been replaced with an animated shaped
- if (charData.t === 1) {
- glyphElement = new SVGCompElement(charData.data, this.globalData, this);
- } else {
- var data = emptyShapeData;
- if (charData.data && charData.data.shapes) {
- data = this.buildShapeData(charData.data, documentData.finalSize);
- }
- glyphElement = new SVGShapeElement(data, this.globalData, this);
- }
- if (this.textSpans[i].glyph) {
- var glyph = this.textSpans[i].glyph;
- this.textSpans[i].childSpan.removeChild(glyph.layerElement);
- glyph.destroy();
- }
- this.textSpans[i].glyph = glyphElement;
- glyphElement._debug = true;
- glyphElement.prepareFrame(0);
- glyphElement.renderFrame();
- this.textSpans[i].childSpan.appendChild(glyphElement.layerElement);
- // when using animated shapes, the layer will be scaled instead of replacing the internal scale
- // this might have issues with strokes and might need a different solution
- if (charData.t === 1) {
- this.textSpans[i].childSpan.setAttribute('transform', 'scale(' + documentData.finalSize / 100 + ',' + documentData.finalSize / 100 + ')');
- }
- } else {
- if (singleShape) {
- tSpan.setAttribute('transform', 'translate(' + matrixHelper.props[12] + ',' + matrixHelper.props[13] + ')');
- }
- tSpan.textContent = letters[i].val;
- tSpan.setAttributeNS('http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve');
- }
- //
- }
- if (singleShape && tSpan) {
- tSpan.setAttribute('d', shapeStr);
- }
- }
- while (i < this.textSpans.length) {
- this.textSpans[i].span.style.display = 'none';
- i += 1;
- }
- this._sizeChanged = true;
- };
- SVGTextLottieElement.prototype.sourceRectAtTime = function () {
- this.prepareFrame(this.comp.renderedFrame - this.data.st);
- this.renderInnerContent();
- if (this._sizeChanged) {
- this._sizeChanged = false;
- var textBox = this.layerElement.getBBox();
- this.bbox = {
- top: textBox.y,
- left: textBox.x,
- width: textBox.width,
- height: textBox.height,
- };
- }
- return this.bbox;
- };
- SVGTextLottieElement.prototype.getValue = function () {
- var i;
- var len = this.textSpans.length;
- var glyphElement;
- this.renderedFrame = this.comp.renderedFrame;
- for (i = 0; i < len; i += 1) {
- glyphElement = this.textSpans[i].glyph;
- if (glyphElement) {
- glyphElement.prepareFrame(this.comp.renderedFrame - this.data.st);
- if (glyphElement._mdf) {
- this._mdf = true;
- }
- }
- }
- };
- SVGTextLottieElement.prototype.renderInnerContent = function () {
- this.validateText();
- if (!this.data.singleShape || this._mdf) {
- this.textAnimator.getMeasures(this.textProperty.currentData, this.lettersChangedFlag);
- if (this.lettersChangedFlag || this.textAnimator.lettersChangedFlag) {
- this._sizeChanged = true;
- var i;
- var len;
- var renderedLetters = this.textAnimator.renderedLetters;
- var letters = this.textProperty.currentData.l;
- len = letters.length;
- var renderedLetter;
- var textSpan;
- var glyphElement;
- for (i = 0; i < len; i += 1) {
- if (!letters[i].n) {
- renderedLetter = renderedLetters[i];
- textSpan = this.textSpans[i].span;
- glyphElement = this.textSpans[i].glyph;
- if (glyphElement) {
- glyphElement.renderFrame();
- }
- if (renderedLetter._mdf.m) {
- textSpan.setAttribute('transform', renderedLetter.m);
- }
- if (renderedLetter._mdf.o) {
- textSpan.setAttribute('opacity', renderedLetter.o);
- }
- if (renderedLetter._mdf.sw) {
- textSpan.setAttribute('stroke-width', renderedLetter.sw);
- }
- if (renderedLetter._mdf.sc) {
- textSpan.setAttribute('stroke', renderedLetter.sc);
- }
- if (renderedLetter._mdf.fc) {
- textSpan.setAttribute('fill', renderedLetter.fc);
- }
- }
- }
- }
- }
- };
- export default SVGTextLottieElement;
|