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.

327 lines 19.8 kB
import { CanvasElementHandler } from "../../CanvasElementHandler"; import Environment from "@aurigma/design-atoms-model/Utils/Environment"; import { RotatedRectangleF, PointF, EqualsOfFloatNumbers } from "@aurigma/design-atoms-model/Math"; import * as _ from "underscore"; import { addClassToElement } from "../../Utils/Dom"; import { ArgumentException } from "@aurigma/design-atoms-model/Exception"; import { alignRectToRect } from "../../Utils/Math"; import { CoordinatesConvertUtils } from "../../Utils/CoordinatesConvertUtils"; import { OriginPointType } from "@aurigma/design-atoms-interfaces"; var FloatingToolbarElementHandler = /** @class */ (function () { function FloatingToolbarElementHandler(_canvasElementHandler, _viewer, _cssClass, _bigButtonCssClass) { var _this = this; this._canvasElementHandler = _canvasElementHandler; this._viewer = _viewer; this._cssClass = _cssClass; this._bigButtonCssClass = _bigButtonCssClass; this._buttonElements = new Map(); this._toolbarElementId = "floatingItemToolbarDiv"; this._centerPositionBottomOffset = 10; this._visible = false; this._stopPropagationFnc = function (e) { e.stopPropagation(); }; this._createButtonFromDescription = function (description) { var handler = description.handler, cssClass = description.cssClass, defaultText = description.defaultText; var toolbarButton = document.createElement("button"); toolbarButton.type = "button"; toolbarButton.addEventListener("mousedown", _this._stopPropagationFnc); toolbarButton.addEventListener("dblclick", _this._stopPropagationFnc); toolbarButton.addEventListener("touchstart", _this._stopPropagationFnc); toolbarButton.value = defaultText; toolbarButton.addEventListener("click", handler); addClassToElement(cssClass, toolbarButton); return toolbarButton; }; } FloatingToolbarElementHandler.prototype.init = function (buttonDescriptions) { var _this = this; if (this._viewer == null) throw new ArgumentException("FloatingToolbarElementHandler.initFloatingItemToolbar: this._viewer cannot be null!"); if (buttonDescriptions == null || buttonDescriptions.size === 0) throw new ArgumentException("FloatingToolbarElementHandler.initFloatingItemToolbar: buttonDescriptions cannot be empty!"); if (this._descriptions != null) throw new ArgumentException("FloatingToolbarElementHandler.initFloatingItemToolbar: toolbar have already initialized!"); this._descriptions = buttonDescriptions; this._toolbarElement = this._createRootElement(); var parent = this._toolbarElement.querySelector("#" + this._toolbarElementId); buttonDescriptions.forEach(function (desc, key) { var buttonElement = _this._createButtonFromDescription(desc); _this._buttonElements.set(key, buttonElement); parent.appendChild(buttonElement); }); this._canvasElementHandler.addChild(this._toolbarElement); this.update(); }; FloatingToolbarElementHandler.prototype.changeButtonsVisibility = function (params) { var _this = this; if (_.isEmpty(params)) throw new ArgumentException("FloatingToolbarElementHandler.changeButtonVisibility: params cannot be empty"); params.forEach(function (p) { return _this._changeButtonVisibility(p.id, p.visible); }); this.update(); }; FloatingToolbarElementHandler.prototype._changeButtonVisibility = function (id, visible) { if (!this._descriptions.has(id)) throw new ArgumentException("FloatingToolbarElementHandler.changeButtonVisibility: There is no button with id='" + id + "' in descriptors map."); var descriptor = this._descriptions.get(id); if (descriptor.visible === visible) return false; descriptor.visible = visible; return true; }; FloatingToolbarElementHandler.prototype.dispose = function () { var _this = this; var _a, _b; this._descriptions = null; (_a = this._buttonElements) === null || _a === void 0 ? void 0 : _a.forEach(function (button) { button.removeEventListener("click", _this._stopPropagationFnc); button.removeEventListener("mousedown", _this._stopPropagationFnc); button.removeEventListener("dblclick", _this._stopPropagationFnc); }); (_b = this._toolbarElement) === null || _b === void 0 ? void 0 : _b.remove(); }; FloatingToolbarElementHandler.prototype.changeVisibility = function (value) { this._visible = value; return this._updateVisibility(); }; Object.defineProperty(FloatingToolbarElementHandler.prototype, "visible", { get: function () { return this._visible; }, enumerable: true, configurable: true }); Object.defineProperty(FloatingToolbarElementHandler.prototype, "isElementVisible", { get: function () { return this._visible && this._isAtLeastOneButtonElementIsVisible; }, enumerable: true, configurable: true }); FloatingToolbarElementHandler.prototype._updateVisibility = function () { var atLeastOneButtonElementIsVisible = this._isAtLeastOneButtonElementIsVisible; var visible = this._visible && atLeastOneButtonElementIsVisible; this.isElementVisible ? CanvasElementHandler.showElement(this._toolbarElement, !atLeastOneButtonElementIsVisible) : CanvasElementHandler.hideElement(this._toolbarElement, !atLeastOneButtonElementIsVisible); return visible; }; Object.defineProperty(FloatingToolbarElementHandler.prototype, "_isAtLeastOneButtonElementIsVisible", { get: function () { return Array.from(this._descriptions.values()).map(function (d) { return d.visible; }).some(function (v) { return v; }); }, enumerable: true, configurable: true }); FloatingToolbarElementHandler.prototype.update = function () { var _this = this; this._updateVisibility(); this._descriptions.forEach(function (description, key) { var element = _this._buttonElements.get(key); element.style.display = description.visible ? "block" : "none"; }); }; FloatingToolbarElementHandler.prototype.hitTest = function (pt) { var divContentRect = this._viewer.canvas.getButtonGroupRectInGripsDiv(this._toolbarElement); return divContentRect.contains(pt); }; FloatingToolbarElementHandler.prototype._createRootElement = function () { var buttonDiv = document.createElement("div"); buttonDiv.style.position = "absolute"; buttonDiv.id = "buttonDiv"; var floatingItemToolbarDiv = document.createElement("div"); floatingItemToolbarDiv.style.display = "flex"; floatingItemToolbarDiv.id = this._toolbarElementId; addClassToElement(this._cssClass, floatingItemToolbarDiv); if (Environment.IsTouchDevice()) addClassToElement(this._bigButtonCssClass, floatingItemToolbarDiv); buttonDiv.appendChild(floatingItemToolbarDiv); return buttonDiv; }; FloatingToolbarElementHandler.prototype.updatePosition = function (rectangle, mode) { if (mode === void 0) { mode = UpdatePositionMode.Smart; } return mode === UpdatePositionMode.Smart || this.isToolbarLargerThanRectangle(rectangle) ? this._smartUpdatePosition(rectangle) : this._updatePositionOnCenter(rectangle); }; FloatingToolbarElementHandler.prototype.isToolbarLargerThanRectangle = function (rectangle) { var w = this._toolbarElement.offsetWidth; var h = this._toolbarElement.offsetHeight + this._centerPositionBottomOffset; var itemRect = CoordinatesConvertUtils.workspaceToControlRectangle(rectangle.bounds, this._viewer); return w > itemRect.width || h > itemRect.height; }; FloatingToolbarElementHandler.prototype._smartUpdatePosition = function (rectangle) { var currentAngleRotate = rectangle.angle % 360; var rotatedRect = CanvasElementHandler.rotateRectangle(rectangle, this._viewer); var z = this._viewer.zoom; var hs = this._viewer.screenXDpi / 72 * z; var vs = this._viewer.screenYDpi / 72 * z; var rectWidth = Math.floor(rotatedRect.width * hs); var rectHeight = Math.floor(rotatedRect.height * vs); var containerWidth = this._toolbarElement.offsetWidth; var containerHeight = this._toolbarElement.offsetHeight; var abovePositionMultiplier = 3.5; var isPositionAboveObject = (containerWidth * abovePositionMultiplier) > rectWidth || (containerHeight * abovePositionMultiplier) > rectHeight; var margin = 8; var offsetX = (isPositionAboveObject ? -containerWidth / 2 : margin) + containerWidth / 2; var offsetY = (isPositionAboveObject ? -containerHeight : margin) + containerHeight / 2; var offsetPoint = new PointF(offsetX, offsetY); offsetPoint.rotate(rotatedRect.angle); var containerPosition = CoordinatesConvertUtils.workspaceToControlPoint(rotatedRect.getUpperRightCorner(), this._viewer); var futurePositionContainer = new PointF(0, 0); futurePositionContainer.x = Math.max(0, containerPosition.x); futurePositionContainer.y = Math.max(0, containerPosition.y); var rotateAngle = this._viewer.contentAngle; if (currentAngleRotate >= 0 && currentAngleRotate < 90) { var corners = [ CoordinatesConvertUtils.workspaceToControlPoint(rotatedRect.getUpperLeftCorner(), this._viewer), CoordinatesConvertUtils.workspaceToControlPoint(rotatedRect.getUpperRightCorner(), this._viewer), CoordinatesConvertUtils.workspaceToControlPoint(rotatedRect.getBottomRightCorner(), this._viewer), CoordinatesConvertUtils.workspaceToControlPoint(rotatedRect.getBottomLeftCorner(), this._viewer) ]; // topLeftCorner, topRightCorner, bottomRightCorner, bottomLeftCorner futurePositionContainer = this._findBetter(corners, rotateAngle, futurePositionContainer, containerHeight, containerWidth); } else if (currentAngleRotate >= 180 && currentAngleRotate < 270) { var corners = [ CoordinatesConvertUtils.workspaceToControlPoint(rotatedRect.getBottomRightCorner(), this._viewer), CoordinatesConvertUtils.workspaceToControlPoint(rotatedRect.getBottomLeftCorner(), this._viewer), CoordinatesConvertUtils.workspaceToControlPoint(rotatedRect.getUpperLeftCorner(), this._viewer), CoordinatesConvertUtils.workspaceToControlPoint(rotatedRect.getUpperRightCorner(), this._viewer) ]; // topLeftCorner, topRightCorner, bottomRightCorner, bottomLeftCorner futurePositionContainer = this._findBetter(corners, rotateAngle, futurePositionContainer, containerHeight, containerWidth); } else if (currentAngleRotate >= 270) { var corners = [ CoordinatesConvertUtils.workspaceToControlPoint(rotatedRect.getUpperRightCorner(), this._viewer), CoordinatesConvertUtils.workspaceToControlPoint(rotatedRect.getBottomRightCorner(), this._viewer), CoordinatesConvertUtils.workspaceToControlPoint(rotatedRect.getBottomLeftCorner(), this._viewer), CoordinatesConvertUtils.workspaceToControlPoint(rotatedRect.getUpperLeftCorner(), this._viewer) ]; // topLeftCorner, topRightCorner, bottomRightCorner, bottomLeftCorner futurePositionContainer = this._findBetter(corners, rotateAngle, futurePositionContainer, containerHeight, containerWidth); } else { // 90-180 var corners = [ CoordinatesConvertUtils.workspaceToControlPoint(rotatedRect.getBottomLeftCorner(), this._viewer), CoordinatesConvertUtils.workspaceToControlPoint(rotatedRect.getUpperLeftCorner(), this._viewer), CoordinatesConvertUtils.workspaceToControlPoint(rotatedRect.getUpperRightCorner(), this._viewer), CoordinatesConvertUtils.workspaceToControlPoint(rotatedRect.getBottomRightCorner(), this._viewer) ]; // topLeftCorner, topRightCorner, bottomRightCorner, bottomLeftCorner futurePositionContainer = this._findBetter(corners, rotateAngle, futurePositionContainer, containerHeight, containerWidth); } this._toolbarElement.style.left = futurePositionContainer.x - 12 + "px"; this._toolbarElement.style.top = futurePositionContainer.y + "px"; }; FloatingToolbarElementHandler.prototype._findBetter = function (corners, rotateAngle, futurePositionContainer, containerHeight, containerWidth) { /* Search better position in the following order: top(1), right(2), left(3), bottom(4). If found then find the best position in it: - if the area is top or bottom, then the position is horizontal; - if the area is to the right or left, then the position is vertical. If don`t found better position, then top right corner(5). */ var _this = this; switch (rotateAngle) { case 90: corners = corners.concat(corners.splice(0, 3)); break; case 180: corners = corners.concat(corners.splice(0, 2)); break; case 270: corners = corners.concat(corners.splice(0, 1)); break; default: // 0 degree`s break; } var topCornerPosition = corners[0]; var topRightCornerPosition = corners[1]; // container position old var bottomCornerPosition = corners[2]; var leftCornerPosition = corners[3]; var stopLineRight = this._viewer.element.offsetWidth - (topRightCornerPosition.x + (containerWidth / 2)); var stopLineBottom = this._viewer.element.offsetHeight - bottomCornerPosition.y; var yCoordination = topCornerPosition.y - 12; var rotateCircle = document.querySelector("div#rotate-circle"); var circleRadius = 15; var rotateCirclePosition = null; if (rotateCircle) { var pageRotateCircleOffset = rotateCircle.getBoundingClientRect(); rotateCirclePosition = CoordinatesConvertUtils.pageToControlPoint(new PointF(pageRotateCircleOffset.left, pageRotateCircleOffset.top), this._viewer); } var rotateCircleCovered = function () { return rotateCirclePosition != null && (rotateCirclePosition.y + circleRadius > futurePositionContainer.y && rotateCirclePosition.y - circleRadius < futurePositionContainer.y + containerHeight) && (rotateCirclePosition.x + 2 * circleRadius > futurePositionContainer.x && rotateCirclePosition.x - 2 * circleRadius < futurePositionContainer.x + containerWidth); }; var calculatedHorizontalPosition = function () { if (stopLineRight < 0) futurePositionContainer.x = topRightCornerPosition.x - (containerWidth / 2) - 5 + stopLineRight; else futurePositionContainer.x = topRightCornerPosition.x - (containerWidth / 2) - 5; if (rotateCircleCovered()) if (stopLineRight > 0 && (_this._viewer.element.offsetWidth - (rotateCirclePosition.x + 2 * circleRadius + containerWidth + 5)) > 0) futurePositionContainer.x = rotateCirclePosition.x + 2 * circleRadius; else futurePositionContainer.x = rotateCirclePosition.x - circleRadius - containerWidth; return futurePositionContainer.x; }; var calculatedVerticalPosition = function () { if (topCornerPosition.y - containerHeight > 0) futurePositionContainer.y = topCornerPosition.y - containerHeight; else futurePositionContainer.y = 0; if (rotateCircleCovered()) futurePositionContainer.y = rotateCirclePosition.y + circleRadius; return futurePositionContainer.y; }; if (yCoordination > containerHeight) { // 1 futurePositionContainer.y = topCornerPosition.y - containerHeight - 12; futurePositionContainer.x = calculatedHorizontalPosition(); } else { if (stopLineRight - (containerWidth / 2 + 5) > 0) { // 2 futurePositionContainer.x = topRightCornerPosition.x + 5; futurePositionContainer.y = calculatedVerticalPosition(); } else if (stopLineRight - (containerWidth / 2 + 5) < 0) { // 3 if (leftCornerPosition.x - containerWidth - 5 > 5) { futurePositionContainer.x = leftCornerPosition.x - containerWidth - 5; futurePositionContainer.y = calculatedVerticalPosition(); } else { // 4 futurePositionContainer.x = calculatedHorizontalPosition(); if (stopLineBottom > containerHeight) { futurePositionContainer.y = bottomCornerPosition.y; } else { // 5 futurePositionContainer.y = calculatedVerticalPosition(); } } } } futurePositionContainer.x += this._viewer.element.scrollLeft; futurePositionContainer.y += this._viewer.element.scrollTop; return futurePositionContainer; }; FloatingToolbarElementHandler.prototype._updatePositionOnCenter = function (rectangle) { if (!(EqualsOfFloatNumbers(rectangle.angle % 90, 0) && !EqualsOfFloatNumbers(rectangle.angle, 360))) throw new ArgumentException("FloatingToolbarElementHandler._updatePositionOnCenter: mode supports only rectangles without angle"); var controlRectangle = CanvasElementHandler.getControlRectangle(rectangle, this._viewer); var w = this._toolbarElement.offsetWidth; var h = this._toolbarElement.offsetHeight; var angle = rectangle.angle; var toolbarRectangle = RotatedRectangleF.FromLTRB(0, 0, w, h); var itemRectangle = RotatedRectangleF.fromRectangleF(RotatedRectangleF.fromRectangleF(controlRectangle, angle).bounds); var targetRect = alignRectToRect(toolbarRectangle, itemRectangle, OriginPointType.Center, OriginPointType.Bottom).bounds; this._toolbarElement.style.left = targetRect.left + "px"; this._toolbarElement.style.top = (targetRect.top - this._centerPositionBottomOffset) + "px"; }; return FloatingToolbarElementHandler; }()); export { FloatingToolbarElementHandler }; export var UpdatePositionMode; (function (UpdatePositionMode) { UpdatePositionMode[UpdatePositionMode["Smart"] = 0] = "Smart"; UpdatePositionMode[UpdatePositionMode["Center"] = 1] = "Center"; })(UpdatePositionMode || (UpdatePositionMode = {})); //# sourceMappingURL=FloatingToolbarElementHandler.js.map