/* * (c) Copyright Ascensio System SIA 2010-2024 * * This program is a free software product. You can redistribute it and/or * modify it under the terms of the GNU Affero General Public License (AGPL) * version 3 as published by the Free Software Foundation. In accordance with * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect * that Ascensio System SIA expressly excludes the warranty of non-infringement * of any third-party rights. * * This program is distributed WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html * * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish * street, Riga, Latvia, EU, LV-1050. * * The interactive user interfaces in modified source and object code versions * of the Program must display Appropriate Legal Notices, as required under * Section 5 of the GNU AGPL version 3. * * Pursuant to Section 7(b) of the License you must retain the original Product * logo when distributing the program. Pursuant to Section 7(e) we decline to * grant you any rights under trademark law for use of our trademarks. * * All the Product's GUI elements, including illustrations and icon sets, as * well as technical writing content are licensed under the terms of the * Creative Commons Attribution-ShareAlike 4.0 International. See the License * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode * */ "use strict"; (function (window, undefined) { function CPoint(x, y, bTemporary) { this.x = x; this.y = y; this.bTemporary = bTemporary === true; } CPoint.prototype.reset = function (x, y, bTemporary) { this.x = x; this.y = y; this.bTemporary = bTemporary === true; }; CPoint.prototype.distance = function (x, y) { var dx = this.x - x; var dy = this.y - y; return Math.sqrt(dx * dx + dy * dy); }; CPoint.prototype.distanceFromOther = function (oPoint) { return this.distance(oPoint.x, oPoint.y); }; CPoint.prototype.isNear = function (x, y) { return this.distance(x, y) < 1; }; CPoint.prototype.serialize = function (w) { w.WriteDouble(this.x); w.WriteDouble(this.y); w.WriteBool(this.bTemporary); }; CPoint.prototype.deserialize = function (r) { this.x = r.GetDouble(); this.y = r.GetDouble(); this.bTemporary = r.GetBool(); }; function PolyLine(drawingObjects, theme, master, layout, slide, pageIndex) { AscFormat.ExecuteNoHistory(function () { this.drawingObjects = drawingObjects; this.arrPoint = []; this.Matrix = new AscCommon.CMatrix(); this.TransformMatrix = new AscCommon.CMatrix(); this.pageIndex = pageIndex; this.style = AscFormat.CreateDefaultShapeStyle(); var style = this.style; style.fillRef.Color.Calculate(theme, slide, layout, master, {R: 0, G: 0, B: 0, A: 255}); var RGBA = style.fillRef.Color.RGBA; var pen = theme.getLnStyle(style.lnRef.idx, style.lnRef.Color); style.lnRef.Color.Calculate(theme, slide, layout, master); RGBA = style.lnRef.Color.RGBA; const API = Asc.editor || editor; const bInkDraw = API.isInkDrawerOn(); this.bInk = bInkDraw; if (bInkDraw) { pen = API.getInkPen(); } if (pen.Fill) { pen.Fill.calculate(theme, slide, layout, master, RGBA); } // adding annots if (Asc.editor.isStartAddAnnot) { pen = Asc.editor.addAnnotPen; } this.pen = pen; this.polylineForDrawer = new PolylineForDrawer(this); this.overlayObject = this.polylineForDrawer; this.continuousRanges = []; let oAnnot = Asc.editor.getAnnotations(); if(oAnnot) { oAnnot.onCreatePolylineTrack(this, drawingObjects.drawingObjects); } }, this, []); } PolyLine.prototype.Draw = function (graphics) { graphics.SetIntegerGrid(false); graphics.transform3(this.Matrix); const oShapeDrawer = new AscCommon.CShapeDrawer(); oShapeDrawer.fromShape(this, graphics); oShapeDrawer.draw(this); }; PolyLine.prototype.draw = function (oDrawer) { if (AscFormat.isRealNumber(this.pageIndex) && oDrawer.SetCurrentPage) { oDrawer.SetCurrentPage(this.pageIndex); } const oGraphics = oDrawer.Graphics || oDrawer; const API = Asc.editor || editor; const bInkDraw = API.isInkDrawerOn(); const dOldAlpha = oGraphics.globalAlpha; if (bInkDraw) { if (AscFormat.isRealNumber(oGraphics.globalAlpha) && oGraphics.put_GlobalAlpha) { oGraphics.put_GlobalAlpha(false, 1); } } this.polylineForDrawer.Draw(oDrawer); if (AscFormat.isRealNumber(dOldAlpha) && oGraphics.put_GlobalAlpha) { oGraphics.put_GlobalAlpha(true, dOldAlpha); } }; PolyLine.prototype.getBounds = function () { var boundsChecker = new AscFormat.CSlideBoundsChecker(); this.draw(boundsChecker); boundsChecker.Bounds.posX = boundsChecker.Bounds.min_x; boundsChecker.Bounds.posY = boundsChecker.Bounds.min_y; boundsChecker.Bounds.extX = boundsChecker.Bounds.max_x - boundsChecker.Bounds.min_x; boundsChecker.Bounds.extY = boundsChecker.Bounds.max_y - boundsChecker.Bounds.min_y; return boundsChecker.Bounds; }; PolyLine.prototype.getShape = function (bWord, drawingDocument, drawingObjects) { var xMax = this.arrPoint[0].x, yMax = this.arrPoint[0].y, xMin = xMax, yMin = yMax; var i; var bClosed = false; var min_dist; if (drawingObjects) { min_dist = drawingObjects.convertPixToMM(3); } else { min_dist = editor.WordControl.m_oDrawingDocument.GetMMPerDot(3) } var oLastPoint = this.arrPoint[this.arrPoint.length - 1]; var nLastIndex = this.arrPoint.length - 1; if (oLastPoint.bTemporary) { nLastIndex--; } if (nLastIndex > 1) { var dx = this.arrPoint[0].x - this.arrPoint[nLastIndex].x; var dy = this.arrPoint[0].y - this.arrPoint[nLastIndex].y; if (Math.sqrt(dx * dx + dy * dy) < min_dist) { bClosed = true; } } if (this.bInk) { bClosed = false; } var nMaxPtIdx = bClosed ? (nLastIndex - 1) : nLastIndex; for (i = 1; i <= nMaxPtIdx; ++i) { if (this.arrPoint[i].x > xMax) { xMax = this.arrPoint[i].x; } if (this.arrPoint[i].y > yMax) { yMax = this.arrPoint[i].y; } if (this.arrPoint[i].x < xMin) { xMin = this.arrPoint[i].x; } if (this.arrPoint[i].y < yMin) { yMin = this.arrPoint[i].y; } } let shape = this.drawingObjects.createShape(); // if(drawingObjects) // { // shape.setWorksheet(drawingObjects.getWorksheetModel()); // shape.addToDrawingObjects(); // } shape.setSpPr(new AscFormat.CSpPr()); shape.spPr.setParent(shape); shape.spPr.setXfrm(new AscFormat.CXfrm()); shape.spPr.xfrm.setParent(shape.spPr); if (!bWord) { shape.spPr.xfrm.setOffX(xMin); shape.spPr.xfrm.setOffY(yMin); } else { shape.setWordShape(true); shape.spPr.xfrm.setOffX(0); shape.spPr.xfrm.setOffY(0); } shape.spPr.xfrm.setExtX(xMax - xMin); shape.spPr.xfrm.setExtY(yMax - yMin); shape.setStyle(AscFormat.CreateDefaultShapeStyle()); if (this.bInk) { shape.spPr.setLn(this.pen); shape.spPr.setFill(AscFormat.CreateNoFillUniFill()); } // adding annots else if (Asc.editor.isStartAddAnnot) { shape.spPr.setLn(Asc.editor.addAnnotPen.createDuplicate()); shape.spPr.setFill(AscFormat.CreateNoFillUniFill()); } var geometry = new AscFormat.Geometry(); var w = xMax - xMin, h = yMax - yMin; var kw, kh, pathW, pathH; if (w > 0) { pathW = 43200; kw = 43200 / w; } else { pathW = 0; kw = 0; } if (h > 0) { pathH = 43200; kh = 43200 / h; } else { pathH = 0; kh = 0; } geometry.AddPathCommand(0, undefined, bClosed ? "norm" : "none", undefined, pathW, pathH); geometry.AddRect("l", "t", "r", "b"); geometry.AddPathCommand(1, (((this.arrPoint[0].x - xMin) * kw) >> 0) + "", (((this.arrPoint[0].y - yMin) * kh) >> 0) + ""); i = 1; var aRanges = this.continuousRanges; var aRange, nRange; var nEnd; var nPtsCount = this.arrPoint.length; var oPt1, oPt2, oPt3, nPt; for (nRange = 0; nRange < aRanges.length; ++nRange) { aRange = aRanges[nRange]; if (aRange[0] + 1 > nMaxPtIdx) { break; } nPt = aRange[0] + 1; nEnd = Math.min(aRange[1], nMaxPtIdx); while (nPt <= nEnd) { if (nPt + 2 <= nEnd) { //cubic bezier curve oPt1 = this.arrPoint[nPt++]; oPt2 = this.arrPoint[nPt++]; oPt3 = this.arrPoint[nPt++]; geometry.AddPathCommand(5, (((oPt1.x - xMin) * kw) >> 0) + "", (((oPt1.y - yMin) * kh) >> 0) + "", (((oPt2.x - xMin) * kw) >> 0) + "", (((oPt2.y - yMin) * kh) >> 0) + "", (((oPt3.x - xMin) * kw) >> 0) + "", (((oPt3.y - yMin) * kh) >> 0) + ""); } else if (nPt + 1 <= nEnd) { //quad bezier curve oPt1 = this.arrPoint[nPt++]; oPt2 = this.arrPoint[nPt++]; geometry.AddPathCommand(4, (((oPt1.x - xMin) * kw) >> 0) + "", (((oPt1.y - yMin) * kh) >> 0) + "", (((oPt2.x - xMin) * kw) >> 0) + "", (((oPt2.y - yMin) * kh) >> 0) + ""); } else { //lineTo oPt1 = this.arrPoint[nPt++]; geometry.AddPathCommand(2, (((oPt1.x - xMin) * kw) >> 0) + "", (((oPt1.y - yMin) * kh) >> 0) + ""); } } } if (bClosed) { geometry.AddPathCommand(6); } shape.spPr.setGeometry(geometry); shape.setBDeleted(false); shape.recalculate(); shape.x = xMin; shape.y = yMin; return shape; }; PolyLine.prototype.checkAnnotationChanges = function () { let oAnnot = Asc.editor.getAnnotations(); if(oAnnot) { oAnnot.onPolylineTrackChanged(this); } }; PolyLine.prototype.tryAddPoint = function (x, y) { var oLastPoint = this.arrPoint[this.arrPoint.length - 1]; if (!oLastPoint) { this.addPoint(x, y); this.checkAnnotationChanges(); return; } if (oLastPoint.isNear(x, y)) { //oLastPoint.reset(x, y); return; } this.addPoint(x, y); this.checkAnnotationChanges(); }; PolyLine.prototype.createContinuousRange = function () { var nIdx = this.arrPoint.length - 1; this.continuousRanges.push([nIdx, nIdx]); }; PolyLine.prototype.getLastContinuousRange = function () { if (this.continuousRanges.length === 0) { this.createContinuousRange(); } return this.continuousRanges[this.continuousRanges.length - 1]; }; PolyLine.prototype.addPoint = function (x, y, bTemporary) { this.arrPoint.push(new CPoint(x, y, bTemporary)); let oLastRange = this.getLastContinuousRange(); oLastRange[1] = this.arrPoint.length - 1; }; PolyLine.prototype.replaceLastPoint = function (x, y, bTemporary) { let oLastPoint = this.arrPoint[this.arrPoint.length - 1]; if (!oLastPoint) { this.addPoint(x, y, bTemporary); this.checkAnnotationChanges(); return; } oLastPoint.reset(x, y, bTemporary); let oLastRange = this.getLastContinuousRange(); if (oLastRange[0] !== this.arrPoint.length - 1) { this.createContinuousRange(); } this.checkAnnotationChanges(); }; PolyLine.prototype.canCreateShape = function () { var nCount = this.arrPoint.length; if (nCount < 2) { return false; } var oLast = this.arrPoint[this.arrPoint.length - 1]; if (oLast.bTemporary) { --nCount; } return nCount > 1; }; PolyLine.prototype.getPointsCount = function () { return this.arrPoint.length; }; PolyLine.prototype.serialize = function (w) { let nCount = this.arrPoint.length; w.WriteLong(nCount); for(let nPt = 0; nPt < nCount; ++nPt) { this.arrPoint[nPt].serialize(w); } let nRangesCount = this.continuousRanges.length; w.WriteLong(nRangesCount); for(let nRange = 0; nRange < nRangesCount; ++nRange) { let oRange = this.continuousRanges[nRange]; w.WriteLong(oRange[0]); w.WriteLong(oRange[1]); } }; PolyLine.prototype.deserialize = function (r) { this.arrPoint.length = 0; this.continuousRanges.length = 0; let nCount = r.GetLong(); for(let nPt = 0; nPt < nCount; ++nPt) { let oPt = new CPoint(); oPt.deserialize(r); this.arrPoint.push(oPt); } let nRangesCount = r.GetLong(); for(let nRange = 0; nRange < nRangesCount; ++nRange) { let oRange = []; oRange[0] = r.GetLong(); oRange[1] = r.GetLong(); this.continuousRanges.push(oRange); } }; function PolylineForDrawer(polyline) { this.polyline = polyline; this.pen = polyline.pen; this.brush = polyline.brush; this.TransformMatrix = polyline.TransformMatrix; this.Matrix = polyline.Matrix; this.Draw = function (graphics) { graphics.SetIntegerGrid(false); graphics.transform3(this.Matrix); const shape_drawer = new AscCommon.CShapeDrawer(); shape_drawer.fromShape(this, graphics); shape_drawer.draw(this); }; this.draw = function (g) { g._e(); if (this.polyline.arrPoint.length < 2) { return; } g._m(this.polyline.arrPoint[0].x, this.polyline.arrPoint[0].y); for (var i = 1; i < this.polyline.arrPoint.length; ++i) { g._l(this.polyline.arrPoint[i].x, this.polyline.arrPoint[i].y); } g.ds(); }; } //--------------------------------------------------------export---------------------------------------------------- window['AscFormat'] = window['AscFormat'] || {}; window['AscFormat'].PolyLine = PolyLine; })(window);