UNPKG

@aurigma/design-atoms

Version:

Design Atoms is a part of Customer's Canvas SDK which allows for manipulating individual design elements through your code.

215 lines 11.1 kB
import { CurvedTextItem } from "@aurigma/design-atoms-model/Product/Items"; import { NewBaseTextItemHandler } from "./NewBaseTextItemHandler"; import { EqualsOfFloatNumbers, RectangleF, RotatedRectangleF } from "@aurigma/design-atoms-model/Math"; import { TextFrameType } from "@aurigma/design-atoms-text/TextEditor/Enums/TextFrameType"; import { getPathFirstPoint, getPathLastPoint, toTextWhizzPath } from "@aurigma/design-atoms-text/Utils/PathUtils"; import { Graphics } from "../Graphics"; import Environment from "@aurigma/design-atoms-model/Utils/Environment"; import { rectangleEquals } from "../Utils/Math"; import { ItemHandlerState } from "./ItemHandlerState"; import { ListStyleSheetManagerFactory } from "@aurigma/design-atoms-text/TextEditor/Services"; import { GmXmlParser } from "@aurigma/design-atoms-text/Serialization/GmXmlParser"; import { GmXmlSerializer } from "@aurigma/design-atoms-text/Serialization/GmXmlSerializer"; import { ColorPalette } from "@aurigma/design-atoms-text/Serialization/Model/ColorPalette"; import { ItemUtils } from "../Utils/ItemUtils"; import { Paragraph, Span } from "@aurigma/design-atoms-text/Model"; export class NewCurvedTextItemHandler extends NewBaseTextItemHandler { constructor(fontRegistry, textEditorControllerFactory, item, textWhizz = null, apiClient, colorPreviewService, colorParser) { super(fontRegistry, textEditorControllerFactory, item, textWhizz, apiClient, colorPreviewService, colorParser); } get item() { return this._getItem(); } set item(item) { super._setItem(item); } getFramesData() { let data = []; data.push(this.item.textPath); return { type: TextFrameType.pathTextFrame, frames: data }; } ; //TODO: to del updateTextWhizzFrames(handler) { handler.replaceFrame(this._createTextWhizzFrame(), 0); } setTextWhizzWrappingPath(handler) { } getWrappingPathData() { return {}; } _onItemPropertyChanged(sender, propertyName) { switch (propertyName) { case "textPath": case "start": case "end": this.update(null, null, "frame"); break; case "fitToPath": case "fitToPathStep": case "stretch": case "originalFontSize": this.update(); break; default: } super._onItemPropertyChanged(sender, propertyName); } //TODO: to del _addTextWhizzFrames(handler) { handler.addFrame(this._createTextWhizzFrame()); } _getEndTransformTrigger(resized) { return resized ? null : "frame"; } async waitInitFrontEndRendering() { await super.waitInitFrontEndRendering(); await this._resetPreviewScale(this.item); } async _applyTransform(item, transform, center) { var _a, _b; if (!(item instanceof CurvedTextItem)) return; const limits = this._getPreviewScaleLimits(); let targetScale = transform.scaleY; targetScale = Math.min((_a = limits.max) !== null && _a !== void 0 ? _a : Number.MAX_VALUE, targetScale); targetScale = Math.max((_b = limits.min) !== null && _b !== void 0 ? _b : Number.MIN_VALUE, targetScale); await this._scaleFontSizes(item, targetScale); await this._updateRectangleAfterTextScale(item, transform); const textPath = item.textPath.clone(); textPath.transform(transform, center); item.textPath = textPath; this.textEditorController.updateText("frame", true); } async _updateRectangleAfterTextScale(item, transform) { await this.textEditorController.waitUpdate(); const textBounds = item.sourceRectangle; textBounds.updateByMatrix(transform.toMatrix()); const rectangle = new RectangleF(textBounds.left, textBounds.top, textBounds.width, textBounds.height); await this.updateRectangle(rectangle, false); } async _scaleFontSizes(item, scaleFactor) { await this._scaleFontSizesInItem(item, scaleFactor); await this._scaleFontSizesInMarkup(item, scaleFactor); await this.textEditorController.waitUpdate(); } async _scaleFontSizesInItem(item, scaleFactor) { item.font.size *= scaleFactor; item.leading *= scaleFactor; } async _scaleFontSizesInMarkup(item, scaleFactor) { const textParser = new GmXmlParser(this._colorParser); const textSerializer = new GmXmlSerializer(this._colorParser); const listStyleSheetManagerFactory = new ListStyleSheetManagerFactory(); let listStyleSheetManager = listStyleSheetManagerFactory.create(); listStyleSheetManager.initialize(); const colorPalette = new ColorPalette(await ItemUtils.getColorPalette(item, this._colorPreviewService)); const textModel = textParser.parse(item.text, colorPalette, item.font.size, listStyleSheetManager); this._scaleTextModelStyles(textModel, scaleFactor); const updatedText = textSerializer.serialize(textModel, colorPalette); item.text = updatedText; } _scaleTextModelStyles(textModel, previewScale) { textModel.blocks.forEach(block => { if (block instanceof Paragraph) { block.inlineElements.forEach(inlineElement => { if (inlineElement instanceof Span) { const spanStyle = inlineElement.style; if (spanStyle === null || spanStyle === void 0 ? void 0 : spanStyle.fontSize) { spanStyle.fontSize.value *= previewScale; } } }); } }); } async _resetPreviewScale(item) { const scale = this.item.previewScale; const eps = 0.0000001; if (Math.abs(scale - 1) > eps) { this.item.previewScale = 1; await this._scaleFontSizes(item, scale); } } //TODO: to del _createTextWhizzFrame() { const path = toTextWhizzPath(this._textWhizz, this.item.textPath); const scale = this.item.previewScale; if (!EqualsOfFloatNumbers(scale, 1)) path.scale(1 / scale, 1 / scale); const frame = new this._textWhizz.PathTextFrame(); frame.baseline = path; frame.start = this.item.start; frame.end = this.item.end; if (this.item.fitToPath) frame.copyFittingMode = this._textWhizz.CopyFittingMode.fitToWidth; return frame; } async updateRectangle(rectangle, updateFromTextEdit) { if (!updateFromTextEdit) return super.updateRectangle(rectangle, updateFromTextEdit); const inRect = rectangle.clone(); const textRect = RotatedRectangleF.fromRectangleF(rectangle); const angle = this.item.transform.angle; const oldCenter = this.rectangle.center; const newCenter = rectangle.clone().center; const oldPath = this.item.textPath.clone(); // поворачиваем обратно в 0 (приводим в нормализованную систему координат) oldPath.rotateAt(angle, oldCenter); textRect.rotateAt(angle, oldCenter); // сдвигаем систему к новому центру. Теперь вычисляется, где будет новый центр в повернутой системе координат newCenter.rotateAt(this.item.transform.angle, oldCenter); // Второй поворот (возвращаем обратно). Всё обратно поворачивается, но уже относительно нового центра // Это нужно, чтобы сохранить правильное положение текста, даже если блок изменил форму или размеры oldPath.rotateAt(-angle, newCenter); textRect.rotateAt(-angle, newCenter); this.item.setTextPath(oldPath, true); rectangle = textRect.toRectangleF(); super.updateRectangle(rectangle, updateFromTextEdit); if (this.hasLayoutAncestor) return; // Не знаю для чего нужен код ниже, updateText("frame") всеравно будет вызван // в BaseTextItemHandler. С помощью чего и применятся новые координаты ректангла на текст. // Может это какая-то мера предосторожности при наличии большого кол-ва текствовых элементов. // Кроме того при наличии autoLayout с alignment, он параллельно этому коду двигает ректангл в // cоответствии выбранного alignment-а, что и вызывает бесконечный вызов этой функции const rectangleChanged = !rectangleEquals(inRect, rectangle); if (rectangleChanged && this.textEditor == null) { await this.textEditorController.waitUpdate(); this.textEditorController.updateText("text", true); } } _drawHandlerEffects(ctx) { if (this._needToDrawBaseline()) this._drawBaseline(ctx); } _getBaselineDrawStates() { var _a; return (_a = this.canvas.viewerConfiguration.curvedTextBaselineDrawStates) !== null && _a !== void 0 ? _a : [ItemHandlerState.edit, ItemHandlerState.select, ItemHandlerState.hover, ItemHandlerState.move, ItemHandlerState.resize, ItemHandlerState.rotate]; } _drawBaseline(ctx) { var _a; try { const scale = Environment.screenDpi * this.canvas.workspace.zoom / 72; const transform = this.item.transform.clone(); const path = this.item.textPath; const center = this.getControlCenter(); const baselineColor = (_a = this.canvas.style) === null || _a === void 0 ? void 0 : _a.baselineColor; Graphics.drawPath(ctx, path, center, transform, 1 / scale, baselineColor, 1); const pt1 = getPathFirstPoint(path).clone(); const pt2 = getPathLastPoint(path).clone(); pt1.transform(transform, center); pt2.transform(transform, center); Graphics.drawCross(ctx, pt1.x, pt1.y, 4 / scale, 1 / scale, baselineColor); Graphics.drawCross(ctx, pt2.x, pt2.y, 4 / scale, 1 / scale, baselineColor); } catch (error) { console.error(`Error in _drawBaseline`, error); } } } NewCurvedTextItemHandler.typeName = "NewCurvedTextItemHandler"; //# sourceMappingURL=NewCurvedTextItemHandler.js.map